Skip to content

Commit 5d3a302

Browse files
committed
tests: verify rounding parameter effects for Add/Mul/Div in IEEE mode across rounding modes
1 parent e8f2692 commit 5d3a302

1 file changed

Lines changed: 110 additions & 0 deletions

File tree

arithmetic_rounding_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package float16
2+
3+
import (
4+
"fmt"
5+
"math"
6+
"testing"
7+
)
8+
9+
func modes() []RoundingMode {
10+
return []RoundingMode{
11+
RoundNearestEven,
12+
RoundNearestAway,
13+
RoundTowardZero,
14+
RoundTowardPositive,
15+
RoundTowardNegative,
16+
}
17+
}
18+
19+
func TestAddWithMode_RoundingMatchesConverter(t *testing.T) {
20+
cases := [][2]float32{
21+
{1.0, float32(math.Pow(2, -11))}, // halfway between 1.0 and next
22+
{1.0, 1e-3}, // general positive
23+
{-1.0, float32(math.Pow(2, -11))}, // negative with halfway increment
24+
{-0.75, 0.125}, // mixed signs, exact binary fractions
25+
}
26+
27+
for _, c := range cases {
28+
for _, m := range modes() {
29+
name := func(a, b float32, mode RoundingMode) string {
30+
return fmt.Sprintf("a=%g b=%g mode=%v", a, b, mode)
31+
}(c[0], c[1], m)
32+
t.Run(name, func(t *testing.T) {
33+
a16 := FromFloat32(c[0])
34+
b16 := FromFloat32(c[1])
35+
expected := FromFloat32WithRounding(a16.ToFloat32()+b16.ToFloat32(), m)
36+
got, err := AddWithMode(a16, b16, ModeIEEEArithmetic, m)
37+
if err != nil {
38+
t.Fatalf("unexpected error: %v", err)
39+
}
40+
if got != expected {
41+
t.Fatalf("AddWithMode mismatch: got=%v want=%v (a=%g b=%g mode=%v)", got, expected, c[0], c[1], m)
42+
}
43+
})
44+
}
45+
}
46+
}
47+
48+
func TestMulWithMode_RoundingMatchesConverter(t *testing.T) {
49+
cases := [][2]float32{
50+
{1.25, 0.2}, // positive * positive
51+
{-1.25, 0.2}, // negative * positive
52+
{1.5, -0.75}, // positive * negative
53+
{-0.5, -0.125}, // negative * negative
54+
{float32(math.Pow(2, -3)), float32(math.Pow(2, -8))}, // exact powers of two
55+
}
56+
57+
for _, c := range cases {
58+
for _, m := range modes() {
59+
name := func(a, b float32, mode RoundingMode) string {
60+
return fmt.Sprintf("a=%g b=%g mode=%v", a, b, mode)
61+
}(c[0], c[1], m)
62+
t.Run(name, func(t *testing.T) {
63+
a16 := FromFloat32(c[0])
64+
b16 := FromFloat32(c[1])
65+
expected := FromFloat32WithRounding(a16.ToFloat32()*b16.ToFloat32(), m)
66+
got, err := MulWithMode(a16, b16, ModeIEEEArithmetic, m)
67+
if err != nil {
68+
t.Fatalf("unexpected error: %v", err)
69+
}
70+
if got != expected {
71+
t.Fatalf("MulWithMode mismatch: got=%v want=%v (a=%g b=%g mode=%v)", got, expected, c[0], c[1], m)
72+
}
73+
})
74+
}
75+
}
76+
}
77+
78+
func TestDivWithMode_RoundingMatchesConverter(t *testing.T) {
79+
cases := [][2]float32{
80+
{1.25, 0.2}, // positive / positive
81+
{-1.25, 0.2}, // negative / positive
82+
{1.5, -0.75}, // positive / negative
83+
{-0.5, -0.125}, // negative / negative
84+
{7.0, 3.0}, // non-terminating in binary
85+
}
86+
87+
for _, c := range cases {
88+
// avoid division by zero
89+
if c[1] == 0 {
90+
continue
91+
}
92+
for _, m := range modes() {
93+
name := func(a, b float32, mode RoundingMode) string {
94+
return fmt.Sprintf("a=%g b=%g mode=%v", a, b, mode)
95+
}(c[0], c[1], m)
96+
t.Run(name, func(t *testing.T) {
97+
a16 := FromFloat32(c[0])
98+
b16 := FromFloat32(c[1])
99+
expected := FromFloat32WithRounding(a16.ToFloat32()/b16.ToFloat32(), m)
100+
got, err := DivWithMode(a16, b16, ModeIEEEArithmetic, m)
101+
if err != nil {
102+
t.Fatalf("unexpected error: %v", err)
103+
}
104+
if got != expected {
105+
t.Fatalf("DivWithMode mismatch: got=%v want=%v (a=%g b=%g mode=%v)", got, expected, c[0], c[1], m)
106+
}
107+
})
108+
}
109+
}
110+
}

0 commit comments

Comments
 (0)