/
floatuntidf.go
106 lines (93 loc) · 2.5 KB
/
floatuntidf.go
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package eos_math
import (
"math"
)
/* Returns: convert a to a double, rounding toward even. */
/* Assumption: double is a IEEE 64 bit floating point type
* tu_int is a 128 bit integral type
*/
/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
func Floatuntidf(a Uint128) float64 {
if a.IsZero() {
return 0.0
}
var N = 128
s := a.High >> 63
a.High = a.High ^ uint64(0)
a.Low = a.Low ^ s - s
sd := N - clzti2_u(a)
e := sd - 1 /* exponent */
if sd > DBL_MANT_DIG {
/* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
* finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
* 12345678901234567890123456
* 1 = msb 1 bit
* P = bit DBL_MANT_DIG-1 bits to the right of 1
* Q = bit DBL_MANT_DIG bits to the right of 1
* R = "or" of all bits to the right of Q
*/
switch sd {
case DBL_MANT_DIG + 1:
a.LeftShift()
case DBL_MANT_DIG + 2:
default:
temp := a
temp.RightShifts(sd - (DBL_MANT_DIG + 2))
minusone := CreateUint128(-1)
minusone.RightShifts((N + DBL_MANT_DIG + 2) - sd)
if a.High&minusone.High != 0 && a.Low&minusone.Low != 0 {
a.High = temp.High | CreateUint128(1).High
a.Low = temp.High | CreateUint128(1).Low
} else {
a.High = temp.High | CreateUint128(0).High
a.Low = temp.High | CreateUint128(0).Low
}
}
/* finish: */
if a.Low&4 != 0 { /* Or P into R */
a.Low = a.Low | 1
}
a = a.Add(CreateUint128(1)) /* round - this step may add a significant bit */
a.RightShifts(2) /* dump Q and R */
/* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
plusone := CreateUint128(1)
plusone.LeftShifts(DBL_MANT_DIG)
a.High = a.High & plusone.High
a.Low = a.Low & plusone.Low
if !a.IsZero() {
a.RightShift()
e += 1
}
/* a is now rounded to DBL_MANT_DIG bits */
} else {
a.RightShifts(DBL_MANT_DIG - sd)
/* a is now rounded to DBL_MANT_DIG bits */
}
var hi uint32
var lo uint32
tempf := a
tempf.RightShifts(32)
hi = uint32((e+1023)<<20) | /* exponent */
(uint32(tempf.Low) & 0x000FFFFF) /* mantissa-high */
lo = uint32(a.Low) /* mantissa-low */
var f64 uint64
f64 = uint64(hi)<<32 + uint64(lo)
return math.Float64frombits(f64)
}
func clzti2_u(a Uint128) int {
var i int
if a.High == 0 {
for a.Low > 0 {
a.Low = a.Low >> 1
i += 1
}
return 128 - i
} else {
for a.High > 0 {
a.High = a.High >> 1
i += 1
}
return 64 - i
}
return 0
}