From f53fb153b6234dc8d6fe112a289a731f22456752 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:00:37 -0400 Subject: [PATCH 1/5] Improve test coverage --- test/mathfuncs.jl | 3 +++ test/runtests.jl | 61 ++++++++++++++++++++++++++++++++++++++++++++--- test/structure.jl | 15 ++++++------ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/test/mathfuncs.jl b/test/mathfuncs.jl index 1d57b32..ac76132 100644 --- a/test/mathfuncs.jl +++ b/test/mathfuncs.jl @@ -19,3 +19,6 @@ for F in (:asec, :acsc, :cosh, :acosh, :acoth) end end + +x,y = rand(Float32, 2) +@test widemul(BFloat16(x), BFloat16(y)) isa Float32 diff --git a/test/runtests.jl b/test/runtests.jl index 58a9ef7..6579f5a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,6 +2,18 @@ using Test, BFloat16s, Printf, Random @info "Testing BFloat16s" BFloat16s.llvm_storage BFloat16s.llvm_arithmetic +@testset "BFloat16s" begin + +@testset "basics" begin + @test Base.exponent_bits(BFloat16) == 8 + @test Base.significand_bits(BFloat16) == 7 + @test precision(BFloat16) == 8 + @test Base.uinttype(BFloat16) == UInt16 + + @test typemin(BFloat16) == -BFloat16s.InfB16 + @test typemax(BFloat16) == BFloat16s.InfB16 +end + @testset "comparisons" begin @test BFloat16(1) < BFloat16(2) @test BFloat16(1f0) < BFloat16(2f0) @@ -18,17 +30,46 @@ using Test, BFloat16s, Printf, Random @test BFloat16(2) != BFloat16(1) @test BFloat16(2f0) != BFloat16(1f0) @test BFloat16(2.0) != BFloat16(1.0) + @test BFloat16(NaN) != BFloat16(1.0) + @test !(BFloat16(1.0) == BFloat16(NaN)) @test iszero(BFloat16(0)) == true @test iszero(BFloat16(3.45)) == false end +@testset "trunc" begin + bf_val = BFloat16(5.5) + @testset "$Ti" for Ti in (Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128) + if !(BFloat16s.llvm_arithmetic && sizeof(Ti) == 16) # Can't use skip argument in @test on 1.6 + @test trunc(Ti, bf_val) == Ti(5) + else + @test_skip trunc(Ti, bf_val) == Ti(5) + end + end + + @test trunc(BFloat16, Float32(π)) == BFloat16(3.140625) + + #InexactError + @test_throws InexactError trunc(Int16, typemax(BFloat16)) + @test_throws InexactError trunc(UInt16, typemax(BFloat16)) +end + @testset "conversions" begin @test Float32(BFloat16(10)) == 1f1 @test Float64(BFloat16(10)) == 10.0 @test Int32(BFloat16(10)) == Int32(10) + @test UInt32(BFloat16(10)) == Int32(10) @test Int64(BFloat16(10)) == Int64(10) + @test UInt64(BFloat16(10)) == Int64(10) @test BFloat16(BigFloat(1)) == BFloat16(1) @test BigFloat(BFloat16(1)) == BigFloat(1) + @test Float16(BFloat16(3.140625)) == Float16(π) + @test BFloat16(Float16(π)) == BFloat16(3.140625) + + @test promote(BFloat16(4.5), Float64(5.0)) == (Float64(4.5), Float64(5.0)) + @test promote(BFloat16(4.5), Float32(5.0)) == (Float32(4.5), Float32(5.0)) + + @test_throws InexactError Int16(typemax(BFloat16)) + @test_throws InexactError UInt16(typemax(BFloat16)) end @testset "abi" begin @@ -44,6 +85,8 @@ end @test BFloat16(2) ^ BFloat16(4) == BFloat16(16) @test eps(BFloat16) == BFloat16(0.0078125) @test sqrt(BFloat16(4f0)) == BFloat16(2f0) + @test rem(BFloat16(3.14), Int) == 3 + @test round(BFloat16(10.4), RoundToZero) == BFloat16(10.0) @test round(BFloat16(10.4), RoundUp) == BFloat16(11.0) @test round(BFloat16(10.6), RoundDown) == BFloat16(10.0) @test round(BFloat16(3.2), RoundNearest) == BFloat16(3.0) @@ -92,6 +135,13 @@ end @test (@sprintf "%a" BFloat16(1.5)) == "0x1.8p+0" end +@testset "show" begin + @test repr(BFloat16(Inf)) == "InfB16" + @test repr(BFloat16(-Inf)) == "-InfB16" + @test repr(BFloat16(NaN)) == "NaNB16" + @test repr(BFloat16(2)) == "BFloat16(2.0)" +end + @testset "random" begin x = Array{BFloat16}(undef, 10) y = Array{BFloat16}(undef, 10) @@ -134,6 +184,9 @@ end @test x < nextfloat(x) @test x > prevfloat(x) + + @test nextfloat(x, typemax(Int)) == typemax(BFloat16) + @test prevfloat(x, typemax(Int)) == typemin(BFloat16) end @test isnan(nextfloat(BFloat16s.NaNB16)) @@ -171,7 +224,7 @@ end end @testset "maxintfloat" begin - + a = maxintfloat(BFloat16) @test a+1-1 == a-1 # the first +1 cannot be represented @test a-1+1 == a # but -1 can @@ -180,7 +233,7 @@ end @testset "rand sampling" begin Random.seed!(123) mi, ma = extrema(rand(BFloat16, 1_000_000)) - + # zero should be the lowest BFloat16 sampled @test mi === zero(BFloat16) @@ -189,4 +242,6 @@ end end include("structure.jl") -include("mathfuncs.jl") \ No newline at end of file +include("mathfuncs.jl") + +end # @testset "BFloat16s" diff --git a/test/structure.jl b/test/structure.jl index 81eb0e1..a9dac48 100644 --- a/test/structure.jl +++ b/test/structure.jl @@ -12,25 +12,26 @@ uint(x::BFloat16) = reinterpret(UInt16, x) @testset "BFloat16 bits" begin @test uint(two) == 0x4000 @test uint(half) == 0x3f00 + @test bitstring(two) == "0100000000000000" + @test bitstring(half) == "0011111100000000" @test signbit(two) == false end @testset "BFloat16 parts" begin @test exponent(whole) == 0 @test significand(whole) == one(BFloat16) - + + # subnormal + @test significand(reinterpret(BFloat16, 0b0000000000000001)) == one(BFloat16) + @test frexp(phi) == (BFloat16(0.80859375), 1) @test ldexp(BFloat16(0.80859375), 1) == phi - + @test exponent(invphi3) == -3 @test significand(invphi3) == BFloat16(1.8828125) - + fr,xp = frexp(invphi3) @test xp == -2 @test fr == BFloat16(0.94140625) @test ldexp(fr, xp) == invphi3 end - - - - From c557bc8cf83943df18dbcf6a1c7515f055f3d672 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Wed, 5 Mar 2025 19:33:38 -0400 Subject: [PATCH 2/5] Add Codecov badge --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1177cce..f6c6560 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # BFloat16s.jl -[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT) +[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT) +[codecov-img]][codecov-url] + +[codecov-img]: https://codecov.io/gh/JuliaMath/BFloat16s.jl/branch/master/graph/badge.svg +[codecov-url]: https://codecov.io/gh/JuliaMath/BFloat16s.jl This package defines the [BFloat16 data type](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format), a floating-point format with 1 sign bit, 8 exponent bits and 7 mantissa bits. From c4ce9089670746866898c7bca16ed658e18193fc Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Wed, 5 Mar 2025 19:53:05 -0400 Subject: [PATCH 3/5] LowPrecArray tests --- test/lowprecarrays.jl | 25 +++++++++++++++++++++++++ test/runtests.jl | 1 + 2 files changed, 26 insertions(+) create mode 100644 test/lowprecarrays.jl diff --git a/test/lowprecarrays.jl b/test/lowprecarrays.jl new file mode 100644 index 0000000..afa3854 --- /dev/null +++ b/test/lowprecarrays.jl @@ -0,0 +1,25 @@ +@testset "lowprecarrays" begin + A = rand(Float32, 10,10) + lpA = LowPrecArray(A) + + @test lpA isa LowPrecArray + @test size(A) == size(lpA) + + lpA[3] = 4 + @test lpA[3] == A[3] + + a = rand(Float32) + ab = BFloat16s.ExpandingBFloat16(a) + b = rand(Float32) + bb = BFloat16s.ExpandingBFloat16(b) + + @test ab isa BFloat16s.ExpandingBFloat16 + @test ab.a isa BFloat16 + @test ab * bb isa Float32 + + B = LowPrecArray(rand(Float32, 10,10)) + C = LowPrecArray(rand(Float32, 10,10)) + + lpA .= B*C + +end # @testset "lowprecarrays" \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 6579f5a..a97e714 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -243,5 +243,6 @@ end include("structure.jl") include("mathfuncs.jl") +include("lowprecarrays.jl") end # @testset "BFloat16s" From 8dc1905316c9433de9cb5b551bdcb5bca6fda654 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Fri, 7 Mar 2025 10:15:24 -0400 Subject: [PATCH 4/5] whitespace --- test/lowprecarrays.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lowprecarrays.jl b/test/lowprecarrays.jl index afa3854..e7d4b41 100644 --- a/test/lowprecarrays.jl +++ b/test/lowprecarrays.jl @@ -22,4 +22,4 @@ lpA .= B*C -end # @testset "lowprecarrays" \ No newline at end of file +end # @testset "lowprecarrays" From aa7edcfac648eb2211bc5c710a962ff9867badd5 Mon Sep 17 00:00:00 2001 From: Christian Guinard <28689358+christiangnrd@users.noreply.github.com> Date: Fri, 7 Mar 2025 14:39:46 -0400 Subject: [PATCH 5/5] Define `Base.issubnormal(x:BFloat16)` --- src/bfloat16.jl | 5 +++++ test/structure.jl | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/bfloat16.jl b/src/bfloat16.jl index ef95afe..e53d6bb 100644 --- a/src/bfloat16.jl +++ b/src/bfloat16.jl @@ -63,6 +63,11 @@ Base.exponent_bits(::Type{BFloat16}) = 8 Base.significand_bits(::Type{BFloat16}) = 7 Base.signbit(x::BFloat16) = (reinterpret(Unsigned, x) & 0x8000) !== 0x0000 +function Base.issubnormal(x::BFloat16) + y = reinterpret(Unsigned, x) + return (y & exponent_mask(BFloat16) == 0) & (y & significand_mask(BFloat16) != 0) +end + function Base.significand(x::BFloat16) xu = reinterpret(Unsigned, x) xs = xu & ~sign_mask(BFloat16) diff --git a/test/structure.jl b/test/structure.jl index a9dac48..63e6f16 100644 --- a/test/structure.jl +++ b/test/structure.jl @@ -22,8 +22,15 @@ end @test significand(whole) == one(BFloat16) # subnormal - @test significand(reinterpret(BFloat16, 0b0000000000000001)) == one(BFloat16) - + @testset "subnormal" begin + allbfs = UInt16(1):typemax(UInt16) + res = map(allbfs) do raw + bf = reinterpret(BFloat16, raw) + issubnormal(bf) == issubnormal(Float32(bf)) + end + @test all(res) + @test significand(reinterpret(BFloat16, 0b0000000000000001)) == one(BFloat16) + end @test frexp(phi) == (BFloat16(0.80859375), 1) @test ldexp(BFloat16(0.80859375), 1) == phi