In main.go are three ways to convert 24.8 fixed value to float64/double type.
The 3d one is my way which is not efficient but is useful to illustrate how to
convert 24.8 fixed value to float64/double
type.--------------------------------程安絮
package main
import (
. "fmt"
"unsafe"
)
func main() {
var u uint64
for u = 0; u < 0x100000000; u++ {
i:=int32(u)
// first way:
// Most languages (e.g. C/Go) encapsulates "value convertions" from int/uint to float
// These convertion ether use cpu directives or (when cpu don't have such directives) use a well-knonwn way to do the same work.
// The key part is `i` must be a signed integer type, `float64(u)/256` will return a wrong float64 value
// Most developers should use this way unless the language you use don't encapsulates "value convertions" from int/uint to float
// This way is much more readable and easy to understand
fA:=float64(i)/256
// second way:
// This function use variant of a well-known way(mentioned in first way) to "value convert" int to float64
// Like first way, the key part is arg `i` must be a signed integer type
// I don't know how it works but I implemented a clumsy way to do the same work
// Most developers should just use the first way, unless the language you use don't encapsulates "value convertions" from int/uint to float
fB:=WlFixedToFloat64(i)
if fA!=fB{
Printf("i: %X\nfGoSimple: %X\nfGo: %X\n", i, fA, fB)
break
}
// My way:
// My clumsy way to "value convert" 24.8 fixed value to float64 value
fC := MyFixedToFloat64(uint32(i))
if fA!=fC{
Printf("i: %X\nfGoSimple: %X\nfC: %X\n", i, fA, fC)
break
}
}//for
} //main
//
func WlFixedToFloat64(f int32) float64 {
u_i := (1023+44)<<52 + (1 << 51) + int64(f)
u_d := *(*float64)( unsafe.Pointer(&u_i) )
return u_d - (3 << 43)
}
func MyFixedToFloat64(fix uint32) float64 {
// fixed value have 1 sign bit and 31 value bits
// decimal point between bit9 and bit8(right to left index order, start at 1)
// get sign bit
var sign uint64 = uint64( fix&0x80000000 )<<32
// if fixed value is positive
if sign==0{
// if value bits is all `0`, return float64 value 0
if fix==0{return 0}
}else{
// if fixed value is negtive
// convert fix bits from complement form to true form
// then put sign bit to zero
fix=((^fix)+1)&0x7fffffff
// there is a special case, when all fix value bits is `0`, (^fix)+1 will overflow
// the really true form should be 0x80000000
if fix==0{fix=0x80000000}
}
// shift out all successive `0`s on the left side and save number of zeros shifted out in `n0`
// the most left `1` will be the hidden bit of Fraction, should be shifted out too
// shift out n0 bits of `0` and 1 bit of `1` on left, pad in n0+1 bits of `0` on the right, so number of value bits is still 32
// decimal point and value bits move together(n0+1bits left), don't change the value;
// decimal point between bit(n0+1+9) and bit(n0+1+8) i.e bit(n0+10) and bit(n0+9)
var n0 uint64
for {
if fix&0x80000000 != 0 {
fix <<=1
break
}
fix <<= 1
n0++
} //for
// float64 have 52 Fraction bits, fix only have 32 bits
// so fix should be convert to uint64 and shift left 20 bits(pad 20bits of `0` on the right side)
// decimal point and value bits move together(20bits left), don't change the value;
// decimal point between bit(20+n0+10) and bit(20+n0+9) i.e bit(30+n0) and bit(29+n0)
var frac uint64 = uint64(fix) << 20
// float64's decimal point between bit53 and bit 52
// so float64's decimal point should move 52-(29+n0)bits right i.e (23-n0)bits right
// move decimal point right equals to increase exponent, so exponent should increase by 22-n0
// float64's exponent Biased up by 1023, so exponent should be 1023+23-n0 i.e 1046-n0
// shift left 52bits put exponent at the correct place
var exp uint64 = (1046 - n0) << 52
// `or` sign, exponent and fraction together, get the float64bits
fBits := sign | exp | frac
// pointer convert float64bits to float64 value
return *(*float64)(unsafe.Pointer(&fBits))
} // func