Yifan
Yifan

Reputation: 1245

Go Float32bit() result not expected

eg: 16777219.0 dec to bit

16777219 -> 1 0000 0000 0000 0000 0000 0011

Mantissa: 23 bit
0000 0000 0000 0000 0000 001

Exponent:
24+127 = 151
151 -> 10010111

Result shoud be:
0_10010111_000 0000 0000 0000 0000 0001

1001011100000000000000000000001

but:

fmt.Printf("%b\n", math.Float32bits(float32(16777219.0)))

// 1001011100000000000000000000010

why the Go Float32bit() result not expected?

reference:


update:

fmt.Printf("16777216.0:%b\n", math.Float32bits(float32(16777216.0)))
fmt.Printf("16777217.0:%b\n", math.Float32bits(float32(16777217.0)))
//16777216.0:1001011100000000000000000000000
//16777217.0:1001011100000000000000000000000
fmt.Printf("16777218.0:%b\n", math.Float32bits(float32(16777218.0)))
//16777218.0:1001011100000000000000000000001
fmt.Printf("16777219.0:%b\n", math.Float32bits(float32(16777219.0)))
fmt.Printf("16777220.0:%b\n", math.Float32bits(float32(16777220.0)))
fmt.Printf("16777221.0:%b\n", math.Float32bits(float32(16777221.0)))
//16777219.0:1001011100000000000000000000010
//16777220.0:1001011100000000000000000000010
//16777221.0:1001011100000000000000000000010

fmt.Printf("000:%f\n", math.Float32frombits(0b_10010111_00000000000000000000000))
// 000:16777216.000000
fmt.Printf("001:%f\n", math.Float32frombits(0b_10010111_00000000000000000000001))
// 001:16777218.000000
fmt.Printf("010:%f\n", math.Float32frombits(0b_10010111_00000000000000000000010))
// 010:16777220.000000
fmt.Printf("011:%f\n", math.Float32frombits(0b_10010111_00000000000000000000011))
// 011:16777222.000000

what is the rules?

Upvotes: 1

Views: 106

Answers (2)

rocka2q
rocka2q

Reputation: 2784

Go gives the correct IEEE-754 binary floating point result - round to nearest, ties to even.

The Go Programming Language Specification

float32     the set of all IEEE-754 32-bit floating-point numbers

Decimal

16777219

is binary

1000000000000000000000011

For 32-bit IEEE-754 floating-point binary binary, the 24-bit integer mantissa is

100000000000000000000001.1

Round to nearest, ties to even gives

100000000000000000000010

Removing the implicit one bit for the 23-bit mantissa gives

00000000000000000000010

package main

import (
    "fmt"
    "math"
)

func main() {
    const n = 16777219
    fmt.Printf("%d\n", n)
    fmt.Printf("%b\n", n)
    f := float32(n)
    fmt.Printf("%g\n", f)
    fmt.Printf("%b\n", math.Float32bits(f))
}

https://go.dev/play/p/yMaVkuiSJ5A

16777219
1000000000000000000000011
1.677722e+07
1001011100000000000000000000010

Upvotes: 1

iBug
iBug

Reputation: 37217

Why the result is not expected: You're expecting the wrong result.

The IEEE 754 standard specifies that, per Wikipedia:

if the number falls midway, it is rounded to the nearest value with an even least significant digit.

So when rounding 16777219, which is midway between 16777218 and 16777218. The "round up" option 16777220 gives an even LSB, and is the correct result you're observing.

Upvotes: 1

Related Questions