Skip to content

Commit

Permalink
FloatPrinter: add Float32 support
Browse files Browse the repository at this point in the history
  • Loading branch information
will committed Apr 29, 2017
1 parent c0de300 commit c0def35
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 155 deletions.
48 changes: 41 additions & 7 deletions spec/std/float_printer/diy_fp_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,46 +48,80 @@ describe DiyFP do
prod.exp.should eq 11 + 13 + 64
end

it "converts ordered" do
it "converts ordered 64" do
ordered = 0x0123456789ABCDEF_u64
f = pointerof(ordered).as(Float64*).value
f.should eq 3512700564088504e-318 # ensure byte order

fp = DiyFP.from_f64(f)
fp = DiyFP.from_f(f)

fp.exp.should eq 0x12 - 0x3FF - 52
# The 52 mantissa bits, plus the implicit 1 in bit 52 as a UINT64.
fp.frac.should eq 0x0013456789ABCDEF
end

it "converts ordered 32" do
ordered = 0x01234567_u32
f = pointerof(ordered).as(Float32*).value
f.should eq(2.9988165487136453e-38_f32)

fp = DiyFP.from_f(f)

fp.exp.should eq 0x2 - 0x7F - 23
# The 23 mantissa bits, plus the implicit 1 in bit 24 as a uint32.

fp.frac.should eq 0xA34567
end

it "converts min f64" do
min = 0x0000000000000001_u64
f = pointerof(min).as(Float64*).value
f.should eq 5e-324 # ensure byte order

fp = DiyFP.from_f64(f)
fp = DiyFP.from_f(f)

fp.exp.should eq -0x3FF - 52 + 1
# This is denormal, so no hidden bit
fp.frac.should eq 1
end

it "converst min f32" do
min = 0x00000001_u32
f = pointerof(min).as(Float32*).value
fp = DiyFP.from_f(f)

fp.exp.should eq -0x7F - 23 + 1
# This is a denormal; so no hidden bit.
fp.frac.should eq 1
end

it "converts max f64" do
max = 0x7fefffffffffffff_u64
f = pointerof(max).as(Float64*).value
f.should eq 1.7976931348623157e308 # ensure byte order

fp = DiyFP.from_f64(f)
fp = DiyFP.from_f(f)

fp.exp.should eq 0x7FE - 0x3FF - 52
fp.frac.should eq 0x001fffffffffffff_u64
end

it "converts max f32" do
max = 0x7f7fffff_u64
f = pointerof(max).as(Float32*).value
f.should eq 3.4028234e38_f32 # ensure byte order

fp = DiyFP.from_f(f)

fp.exp.should eq 0xFE - 0x7F - 23
fp.frac.should eq 0x00ffffff_u64
end

it "normalizes ordered" do
ordered = 0x0123456789ABCDEF_u64
f = pointerof(ordered).as(Float64*).value

fp = DiyFP.from_f64_normalized(f)
fp = DiyFP.from_f_normalized(f)

fp.exp.should eq 0x12 - 0x3FF - 52 - 11
fp.frac.should eq 0x0013456789ABCDEF_u64 << 11
Expand All @@ -97,7 +131,7 @@ describe DiyFP do
min = 0x0000000000000001_u64
f = pointerof(min).as(Float64*).value

fp = DiyFP.from_f64_normalized(f)
fp = DiyFP.from_f_normalized(f)

fp.exp.should eq -0x3FF - 52 + 1 - 63
# This is a denormal; so no hidden bit
Expand All @@ -108,7 +142,7 @@ describe DiyFP do
max = 0x7fefffffffffffff_u64
f = pointerof(max).as(Float64*).value

fp = DiyFP.from_f64_normalized(f)
fp = DiyFP.from_f_normalized(f)

fp.exp.should eq 0x7FE - 0x3FF - 52 - 11
fp.frac.should eq 0x001fffffffffffff << 11
Expand Down
196 changes: 140 additions & 56 deletions spec/std/float_printer/grisu3_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,79 +3,163 @@ require "float_printer/grisu3"
include FloatPrinter

private def test_grisu(v : UInt64)
f = pointerof(v).as(Float64*).value
test_grisu(f)
test_grisu pointerof(v).as(Float64*).value
end

private def test_grisu(v : Float64)
private def test_grisu(v : UInt32)
test_grisu pointerof(v).as(Float32*).value
end

private def test_grisu(v : Float64 | Float32)
buffer = StaticArray(UInt8, 128).new(0_u8)
status, decimal_exponent, length = Grisu3.grisu3(v, buffer.to_unsafe)
point = decimal_exponent + length
return status, point, String.new(buffer.to_unsafe)
end

describe "grisu3" do
it "min float64" do
status, point, str = test_grisu 5e-324
status.should eq true
str.should eq "5"
point.should eq -323
end
context "float64" do
it "min float" do
status, point, str = test_grisu 5e-324
status.should eq true
str.should eq "5"
point.should eq -323
end

it "max float64" do
status, point, str = test_grisu 1.7976931348623157e308
status.should eq true
str.should eq "17976931348623157"
point.should eq 309
end
it "max float" do
status, point, str = test_grisu 1.7976931348623157e308
status.should eq true
str.should eq "17976931348623157"
point.should eq 309
end

it "point at end" do
status, point, str = test_grisu 4294967272.0
status.should eq true
str.should eq "4294967272"
point.should eq 10
end
it "point at end" do
status, point, str = test_grisu 4294967272.0
status.should eq true
str.should eq "4294967272"
point.should eq 10
end

it "large number" do
status, point, str = test_grisu 4.1855804968213567e298
status.should eq true
str.should eq "4185580496821357"
point.should eq 299
end
it "large number" do
status, point, str = test_grisu 4.1855804968213567e298
status.should eq true
str.should eq "4185580496821357"
point.should eq 299
end

it "small number" do
status, point, str = test_grisu 5.5626846462680035e-309
status.should eq true
str.should eq "5562684646268003"
point.should eq -308
end
it "small number" do
status, point, str = test_grisu 5.5626846462680035e-309
status.should eq true
str.should eq "5562684646268003"
point.should eq -308
end

it "another no point move" do
status, point, str = test_grisu 2147483648.0
status.should eq true
str.should eq "2147483648"
point.should eq 10
end
it "another no point move" do
status, point, str = test_grisu 2147483648.0
status.should eq true
str.should eq "2147483648"
point.should eq 10
end

it "failure case" do
# grisu should not be able to do this number
# this number is reused to ensure the fallback works
status, point, str = test_grisu 3.5844466002796428e+298
status.should eq false
str.should_not eq "35844466002796428"
end
it "failure case" do
# grisu should not be able to do this number
# this number is reused to ensure the fallback works
status, point, str = test_grisu 3.5844466002796428e+298
status.should eq false
str.should_not eq "35844466002796428"
end

it "smallest normal" do
status, point, str = test_grisu 0x0010000000000000_u64
status.should eq true
str.should eq "22250738585072014"
point.should eq -307
end

it "smallest normal" do
status, point, str = test_grisu 0x0010000000000000_u64
status.should eq true
str.should eq "22250738585072014"
point.should eq -307
it "largest denormal" do
status, point, str = test_grisu 0x000FFFFFFFFFFFFF_u64
status.should eq true
str.should eq "2225073858507201"
point.should eq -307
end
end

it "largest denormal" do
status, point, str = test_grisu 0x000FFFFFFFFFFFFF_u64
status.should eq true
str.should eq "2225073858507201"
point.should eq -307
context "float32" do
it "min" do
status, point, str = test_grisu 1e-45_f32
status.should eq true
str.should eq "1"
point.should eq -44
end

it "max" do
status, point, str = test_grisu 3.4028234e38_f32
status.should eq true
str.should eq "34028235"
point.should eq 39
end

it "general whole number, rounding" do
status, point, str = test_grisu 4294967272.0_f32
status.should eq true
str.should eq "42949673"
point.should eq 10
end

it "general whole number, rounding" do
status, point, str = test_grisu 4294967272.0_f32
status.should eq true
str.should eq "42949673"
point.should eq 10
end

it "large number, rounding" do
status, point, str = test_grisu 3.32306998946228968226e35_f32
status.should eq true
str.should eq "332307"
point.should eq 36
end

it "small number" do
status, point, str = test_grisu 1.2341e-41_f32
status.should eq true
str.should eq "12341"
point.should eq -40
end

it "general no rounding" do
status, point, str = test_grisu 3.3554432e7_f32
status.should eq true
str.should eq "33554432"
point.should eq 8
end

it "general with rounding up" do
status, point, str = test_grisu 3.26494756798464e14_f32
status.should eq true
str.should eq "32649476"
point.should eq 15
end

it "general with rounding down" do
status, point, str = test_grisu 3.91132223637771935344e37_f32
status.should eq true
str.should eq "39113222"
point.should eq 38
end

it "smallest normal" do
status, point, str = test_grisu 0x00800000_u32
status.should eq true
str.should eq "11754944"
point.should eq -37
end

it "largest denormal" do
status, point, str = test_grisu 0x007FFFFF_u32
status.should eq true
str.should eq "11754942"
point.should eq -37
end
end
end
Loading

0 comments on commit c0def35

Please sign in to comment.