aboutsummaryrefslogtreecommitdiff
path: root/softfloat/s_roundPackToI64.c
blob: c6085e5814608b56b8c536fc9943c140b54cda24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

#include <stdbool.h>
#include <stdint.h>
#include "platform.h"
#include "internals.h"
#include "softfloat.h"

int_fast64_t
 softfloat_roundPackToI64(
     bool sign,
     uint_fast64_t sig64,
     uint_fast64_t sig0,
     int_fast8_t roundingMode,
     bool exact
 )
{
    bool roundNearestEven, increment;
    union { uint64_t ui; int64_t i; } uZ;
    int_fast64_t z;

    roundNearestEven = ( roundingMode == softfloat_round_nearest_even );
    increment = ( UINT64_C( 0x8000000000000000 ) <= sig0 );
    if (
           ! roundNearestEven
        && ( roundingMode != softfloat_round_nearest_maxMag )
    ) {
        increment =
               ( roundingMode != softfloat_round_minMag )
            && ( roundingMode
                     == ( sign ? softfloat_round_min : softfloat_round_max ) )
            && sig0;
    }
    if ( increment ) {
        ++sig64;
        if ( ! sig64 ) goto invalid;
        sig64 &=
            ~ ( ! ( sig0 & UINT64_C( 0x7FFFFFFFFFFFFFFF ) )
                    & roundNearestEven );
    }
    uZ.ui = sign ? - sig64 : sig64;
    z = uZ.i;
    if ( z && ( ( z < 0 ) ^ sign ) ) goto invalid;
    if ( exact && sig0 ) softfloat_raiseFlags( softfloat_flag_inexact );
    return z;
 invalid:
    softfloat_raiseFlags( softfloat_flag_invalid );
    return
        sign ? - INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1
            : INT64_C( 0x7FFFFFFFFFFFFFFF );

}