On 16.10.2013, at 23:10, Tom Musta <tommu...@gmail.com> wrote:

> The comment preceding the float64_to_uint64 routine suggests that
> the implementation is broken.  And this is, indeed, the case.
> 
> This patch properly implements the conversion of a 64-bit floating
> point number to an unsigned, 64 bit integer.
> 
> Note that the patch does not pass scripts/checkpatch.pl because it
> maintains the coding style of fpu/softfloat.c.
> 
> V2: This contribution can be licensed under either the softfloat-2a or -2b
> license.

Missing a SoB line.


Alex

> 
> ---
> fpu/softfloat.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 85 insertions(+), 7 deletions(-)
> 
> diff --git a/fpu/softfloat.c b/fpu/softfloat.c
> index 7ba51b6..f8c7f92 100644
> --- a/fpu/softfloat.c
> +++ b/fpu/softfloat.c
> @@ -204,6 +204,46 @@ static int64 roundAndPackInt64( flag zSign, uint64_t 
> absZ0, uint64_t absZ1 STATU
> }
> 
> /*----------------------------------------------------------------------------
> +| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
> +| `absZ1', with binary point between bits 63 and 64 (between the input 
> words),
> +| and returns the properly rounded 64-bit unsigned integer corresponding to 
> the
> +| input.  Ordinarily, the fixed-point input is simply rounded to an integer,
> +| with the inexact exception raised if the input cannot be represented 
> exactly
> +| as an integer.  However, if the fixed-point input is too large, the invalid
> +| exception is raised and the largest unsigned integer is returned.
> +*----------------------------------------------------------------------------*/
> +
> +static int64 roundAndPackUint64( uint64_t absZ0, uint64_t absZ1 STATUS_PARAM)
> +{
> +    int8 roundingMode;
> +    flag roundNearestEven, increment;
> +    int64_t z;
> +
> +    roundingMode = STATUS(float_rounding_mode);
> +    roundNearestEven = ( roundingMode == float_round_nearest_even );
> +    increment = ( (int64_t) absZ1 < 0 );
> +    if ( ! roundNearestEven ) {
> +        if ( roundingMode == float_round_to_zero ) {
> +            increment = 0;
> +        }
> +        else {
> +            increment = ( roundingMode == float_round_up ) && absZ1;
> +        }
> +    }
> +    if ( increment ) {
> +        ++absZ0;
> +        if ( absZ0 == 0 ) {
> +            float_raise( float_flag_invalid STATUS_VAR);
> +            return LIT64( 0xFFFFFFFFFFFFFFFF );
> +        }
> +        absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven );
> +    }
> +    z = absZ0;
> +    if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact;
> +    return z;
> +}
> +
> +/*----------------------------------------------------------------------------
> | Returns the fraction bits of the single-precision floating-point value `a'.
> *----------------------------------------------------------------------------*/
> 
> @@ -6536,18 +6576,56 @@ uint_fast16_t float64_to_uint16_round_to_zero(float64 
> a STATUS_PARAM)
>     return res;
> }
> 
> -/* FIXME: This looks broken.  */
> -uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
> +/*----------------------------------------------------------------------------
> +| Returns the result of converting the double-precision floating-point value
> +| `a' to the 64-bit unsigned integer format.  The conversion is
> +| performed according to the IEC/IEEE Standard for Binary Floating-Point
> +| Arithmetic---which means in particular that the conversion is rounded
> +| according to the current rounding mode.  If `a' is a NaN, the largest
> +| positive integer is returned.  If the conversion overflows, the
> +| largest unsigned integer is returned.  If 'a' is negative, zero is
> +| returned.
> +*----------------------------------------------------------------------------*/
> +
> +uint64_t float64_to_uint64( float64 a STATUS_PARAM )
> {
> -    int64_t v;
> +    flag aSign;
> +    int_fast16_t aExp, shiftCount;
> +    uint64_t aSig, aSigExtra;
> +    a = float64_squash_input_denormal(a STATUS_VAR);
> 
> -    v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR));
> -    v += float64_val(a);
> -    v = float64_to_int64(make_float64(v) STATUS_VAR);
> +    aSig = extractFloat64Frac( a );
> +    aExp = extractFloat64Exp( a );
> +    aSign = extractFloat64Sign( a );
> +    if ( aSign ) {
> +        if ( aExp ) {
> +            float_raise( float_flag_invalid STATUS_VAR);
> +        } else if ( aSig ) { /* negative denormalized */
> +            float_raise( float_flag_inexact STATUS_VAR);
> +        }
> +        return 0;
> +    }
> +    if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
> +    shiftCount = 0x433 - aExp;
> +    if ( shiftCount <= 0 ) {
> +        if ( 0x43E < aExp ) {
> +            if ( ( aSig != LIT64( 0x0010000000000000 ) ) ||
> +                 ( aExp == 0x7FF ) ) {
> +                float_raise( float_flag_invalid STATUS_VAR);
> +            }
> +            return LIT64( 0xFFFFFFFFFFFFFFFF );
> +        }
> +        aSigExtra = 0;
> +        aSig <<= - shiftCount;
> +    }
> +    else {
> +        shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
> +    }
> +    return roundAndPackUint64( aSig, aSigExtra STATUS_VAR );
> 
> -    return v - INT64_MIN;
> }
> 
> +
> uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
> {
>     int64_t v;
> -- 
> 1.7.1
> 
> 
> 


Reply via email to