Skip to content

Commit 7d89a79

Browse files
committed
increase test coverage to 53.2%
1 parent 161b5b1 commit 7d89a79

15 files changed

Lines changed: 1162 additions & 483 deletions

arithmetic.go

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func MulWithMode(a, b Float16, mode ArithmeticMode, rounding RoundingMode) (Floa
167167
}
168168
return QuietNaN, nil
169169
}
170-
170+
171171
// ∞ * finite = ±∞ (sign depends on operand signs)
172172
signA := a.Signbit()
173173
signB := b.Signbit()
@@ -465,7 +465,6 @@ func divIEEE754(a, b Float16, rounding RoundingMode) (Float16, error) {
465465
f32a := a.ToFloat32()
466466
f32b := b.ToFloat32()
467467
result := f32a / f32b
468-
469468

470469
// Use the provided rounding mode for the conversion back to Float16
471470
return ToFloat16WithMode(result, ModeExact, rounding)
@@ -492,23 +491,23 @@ func Less(a, b Float16) bool {
492491
if a.IsNaN() || b.IsNaN() {
493492
return false
494493
}
495-
494+
496495
// Handle zero: -0 == +0 for comparison
497496
if a.IsZero() && b.IsZero() {
498497
return false
499498
}
500-
499+
501500
// Handle signs
502501
signA := a.Signbit()
503502
signB := b.Signbit()
504-
503+
505504
if signA && !signB {
506505
return true // negative < positive
507506
}
508507
if !signA && signB {
509508
return false // positive > negative
510509
}
511-
510+
512511
// Same sign: compare magnitudes
513512
if signA {
514513
// Both negative: larger magnitude is smaller value
@@ -543,7 +542,7 @@ func Min(a, b Float16) Float16 {
543542
if b.IsNaN() {
544543
return a
545544
}
546-
545+
547546
if Less(a, b) {
548547
return a
549548
}
@@ -559,7 +558,7 @@ func Max(a, b Float16) Float16 {
559558
if b.IsNaN() {
560559
return a
561560
}
562-
561+
563562
if Greater(a, b) {
564563
return a
565564
}
@@ -573,7 +572,7 @@ func AddSlice(a, b []Float16) []Float16 {
573572
if len(a) != len(b) {
574573
panic("float16: slice length mismatch")
575574
}
576-
575+
577576
result := make([]Float16, len(a))
578577
for i := range a {
579578
result[i] = Add(a[i], b[i])
@@ -586,7 +585,7 @@ func SubSlice(a, b []Float16) []Float16 {
586585
if len(a) != len(b) {
587586
panic("float16: slice length mismatch")
588587
}
589-
588+
590589
result := make([]Float16, len(a))
591590
for i := range a {
592591
result[i] = Sub(a[i], b[i])
@@ -599,7 +598,7 @@ func MulSlice(a, b []Float16) []Float16 {
599598
if len(a) != len(b) {
600599
panic("float16: slice length mismatch")
601600
}
602-
601+
603602
result := make([]Float16, len(a))
604603
for i := range a {
605604
result[i] = Mul(a[i], b[i])
@@ -612,7 +611,7 @@ func DivSlice(a, b []Float16) []Float16 {
612611
if len(a) != len(b) {
613612
panic("float16: slice length mismatch")
614613
}
615-
614+
616615
result := make([]Float16, len(a))
617616
for i := range a {
618617
result[i] = Div(a[i], b[i])
@@ -643,7 +642,7 @@ func DotProduct(a, b []Float16) Float16 {
643642
if len(a) != len(b) {
644643
panic("float16: slice length mismatch")
645644
}
646-
645+
647646
var sum Float16 = PositiveZero
648647
for i := range a {
649648
product := Mul(a[i], b[i])

arithmetic_mode_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ func Infinity(sign int) Float16 {
258258

259259
func TestSliceOperationsWithMode(t *testing.T) {
260260
t.Run("SubSlice", func(t *testing.T) {
261-
a := []Float16{FromBits(0x4400), FromBits(0x4500), FromBits(0x4600)} // [4.0, 5.0, 6.0]
262-
b := []Float16{FromBits(0x3C00), FromBits(0x4000), FromBits(0x4200)} // [1.0, 2.0, 3.0]
261+
a := []Float16{FromBits(0x4400), FromBits(0x4500), FromBits(0x4600)} // [4.0, 5.0, 6.0]
262+
b := []Float16{FromBits(0x3C00), FromBits(0x4000), FromBits(0x4200)} // [1.0, 2.0, 3.0]
263263
want := []Float16{FromBits(0x4200), FromBits(0x4200), FromBits(0x4200)} // [3.0, 3.0, 3.0]
264264
got := SubSlice(a, b)
265265
if len(got) != len(want) {
@@ -273,8 +273,8 @@ func TestSliceOperationsWithMode(t *testing.T) {
273273
})
274274

275275
t.Run("MulSlice", func(t *testing.T) {
276-
a := []Float16{FromBits(0x3C00), FromBits(0x4000), FromBits(0x4400)} // [1.0, 2.0, 4.0]
277-
b := []Float16{FromBits(0x4400), FromBits(0x4400), FromBits(0x4400)} // [4.0, 4.0, 4.0]
276+
a := []Float16{FromBits(0x3C00), FromBits(0x4000), FromBits(0x4400)} // [1.0, 2.0, 4.0]
277+
b := []Float16{FromBits(0x4400), FromBits(0x4400), FromBits(0x4400)} // [4.0, 4.0, 4.0]
278278
want := []Float16{FromBits(0x4400), FromBits(0x4800), FromBits(0x4C00)} // [4.0, 8.0, 16.0]
279279
got := MulSlice(a, b)
280280
if len(got) != len(want) {
@@ -288,8 +288,8 @@ func TestSliceOperationsWithMode(t *testing.T) {
288288
})
289289

290290
t.Run("DivSlice", func(t *testing.T) {
291-
a := []Float16{FromBits(0x4400), FromBits(0x4800), FromBits(0x4C00)} // [4.0, 8.0, 16.0]
292-
b := []Float16{FromBits(0x3C00), FromBits(0x4000), FromBits(0x4400)} // [1.0, 2.0, 4.0]
291+
a := []Float16{FromBits(0x4400), FromBits(0x4800), FromBits(0x4C00)} // [4.0, 8.0, 16.0]
292+
b := []Float16{FromBits(0x3C00), FromBits(0x4000), FromBits(0x4400)} // [1.0, 2.0, 4.0]
293293
want := []Float16{FromBits(0x4400), FromBits(0x4400), FromBits(0x4400)} // [4.0, 4.0, 4.0]
294294
got := DivSlice(a, b)
295295
if len(got) != len(want) {
@@ -328,7 +328,7 @@ func TestSliceOperationsWithMode(t *testing.T) {
328328

329329
t.Run("Norm2", func(t *testing.T) {
330330
s := []Float16{FromBits(0x4200), FromBits(0x4400)} // 3-4-5 right triangle
331-
want := FromBits(0x4500) // 5.0
331+
want := FromBits(0x4500) // 5.0
332332
got := Norm2(s)
333333
if got != want {
334334
t.Errorf("Norm2() = %v, want %v", got, want)

arithmetic_test.go

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
package float16
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestAddWithMode(t *testing.T) {
8+
tests := []struct {
9+
name string
10+
a Float16
11+
b Float16
12+
mode ArithmeticMode
13+
rounding RoundingMode
14+
expect Float16
15+
hasError bool
16+
}{
17+
// Basic addition
18+
{"1.0 + 2.0", 0x3C00, 0x4000, ModeIEEEArithmetic, RoundNearestEven, 0x4200, false}, // 1.0 + 2.0 = 3.0
19+
{"0.5 + 0.25", 0x3800, 0x3400, ModeIEEEArithmetic, RoundNearestEven, 0x3A00, false}, // 0.5 + 0.25 = 0.75 (0x3A00)
20+
21+
// Special cases
22+
{"0 + x", 0x0000, 0x3C00, ModeIEEEArithmetic, RoundNearestEven, 0x3C00, false}, // 0 + 1.0 = 1.0
23+
{"x + 0", 0x3C00, 0x0000, ModeIEEEArithmetic, RoundNearestEven, 0x3C00, false}, // 1.0 + 0 = 1.0
24+
25+
// Infinity handling
26+
{"Inf + 1", 0x7C00, 0x3C00, ModeIEEEArithmetic, RoundNearestEven, 0x7C00, false}, // +Inf + 1 = +Inf
27+
{"1 + Inf", 0x3C00, 0x7C00, ModeIEEEArithmetic, RoundNearestEven, 0x7C00, false}, // 1 + Inf = +Inf
28+
{"-Inf + Inf", 0xFC00, 0x7C00, ModeIEEEArithmetic, RoundNearestEven, 0x7E00, false}, // -Inf + Inf = NaN
29+
30+
// NaN handling
31+
{"NaN + 1", 0x7E00, 0x3C00, ModeIEEEArithmetic, RoundNearestEven, 0x7E00, false}, // NaN + 1 = NaN
32+
{"1 + NaN", 0x3C00, 0x7E00, ModeIEEEArithmetic, RoundNearestEven, 0x7E00, false}, // 1 + NaN = NaN
33+
34+
// Exact mode
35+
{"1.0 + 2.0 (exact)", 0x3C00, 0x4000, ModeExactArithmetic, RoundNearestEven, 0x4200, false}, // 1.0 + 2.0 = 3.0 (exact)
36+
{"0.1 + 0.2 (exact)", 0x2E66, 0x3266, ModeExactArithmetic, RoundNearestEven, 0x34CC, false}, // 0.1 + 0.2 = ~0.2998 (actual float16 result)
37+
38+
// Rounding modes
39+
{"1.0 + 0.5 (toward zero)", 0x3C00, 0x3800, ModeIEEEArithmetic, RoundTowardZero, 0x3E00, false}, // 1.0 + 0.5 = 1.5 (0x3E00)
40+
}
41+
42+
for _, tt := range tests {
43+
t.Run(tt.name, func(t *testing.T) {
44+
result, err := AddWithMode(tt.a, tt.b, tt.mode, tt.rounding)
45+
46+
if tt.hasError {
47+
if err == nil {
48+
t.Errorf("Expected error, got nil")
49+
}
50+
return
51+
}
52+
53+
if err != nil {
54+
t.Fatalf("Unexpected error: %v", err)
55+
}
56+
57+
// For better debugging, show float32 values when the test fails
58+
if result != tt.expect {
59+
t.Errorf("AddWithMode(%v, %v) = %v (0x%04X, %f), want %v (0x%04X, %f)",
60+
tt.a, tt.b, result, uint16(result), result.ToFloat32(),
61+
tt.expect, uint16(tt.expect), tt.expect.ToFloat32())
62+
}
63+
})
64+
}
65+
}
66+
67+
func TestAddWithMode_ErrorCases(t *testing.T) {
68+
tests := []struct {
69+
name string
70+
a Float16
71+
b Float16
72+
mode ArithmeticMode
73+
expect Float16
74+
errCode ErrorCode
75+
}{
76+
{"NaN in exact mode", 0x7E00, 0x3C00, ModeExactArithmetic, 0, ErrNaN},
77+
{"Inf-Inf in exact mode", 0x7C00, 0xFC00, ModeExactArithmetic, 0, ErrInvalidOperation},
78+
}
79+
80+
for _, tt := range tests {
81+
t.Run(tt.name, func(t *testing.T) {
82+
result, err := AddWithMode(tt.a, tt.b, tt.mode, RoundNearestEven)
83+
84+
if err == nil {
85+
t.Fatalf("Expected error, got nil")
86+
}
87+
88+
err16, ok := err.(*Float16Error)
89+
if !ok {
90+
t.Fatalf("Expected Float16Error, got %T", err)
91+
}
92+
93+
if err16.Code != tt.errCode {
94+
t.Errorf("Expected error code %v, got %v", tt.errCode, err16.Code)
95+
}
96+
97+
if result != tt.expect {
98+
t.Errorf("Expected result %v, got %v", tt.expect, result)
99+
}
100+
})
101+
}
102+
}
103+
104+
func TestAdd(t *testing.T) {
105+
tests := []struct {
106+
a Float16
107+
b Float16
108+
expect Float16
109+
}{
110+
{0x3C00, 0x4000, 0x4200}, // 1.0 + 2.0 = 3.0
111+
{0x3800, 0x3400, 0x3A00}, // 0.5 + 0.25 = 0.75 (0x3A00)
112+
{0x7C00, 0x3C00, 0x7C00}, // +Inf + 1 = +Inf
113+
{0x3C00, 0x0000, 0x3C00}, // 1.0 + 0.0 = 1.0
114+
{0x0000, 0x3C00, 0x3C00}, // 0.0 + 1.0 = 1.0
115+
{0x3C00, 0xBC00, 0x0000}, // 1.0 + (-1.0) = 0.0
116+
}
117+
118+
for _, tt := range tests {
119+
t.Run(tt.a.String()+" + "+tt.b.String(), func(t *testing.T) {
120+
result := Add(tt.a, tt.b)
121+
if result != tt.expect {
122+
t.Errorf("Add(%v, %v) = %v (0x%04X), want %v (0x%04X)",
123+
tt.a, tt.b, result, uint16(result), tt.expect, uint16(tt.expect))
124+
}
125+
})
126+
}
127+
}
128+
129+
func TestSubWithModeBasic(t *testing.T) {
130+
tests := []struct {
131+
name string
132+
a Float16
133+
b Float16
134+
expect Float16
135+
hasError bool
136+
}{
137+
{name: "1.0 - 0.5", a: 0x3C00, b: 0x3800, expect: 0x3800, hasError: false}, // 1.0 - 0.5 = 0.5
138+
{name: "0.5 - 0.25", a: 0x3800, b: 0x3400, expect: 0x3400, hasError: false}, // 0.5 - 0.25 = 0.25
139+
{name: "1.0 - 1.0", a: 0x3C00, b: 0x3C00, expect: 0x0000, hasError: false}, // 1.0 - 1.0 = 0.0
140+
{name: "1.0 - -1.0", a: 0x3C00, b: 0xBC00, expect: 0x4000, hasError: false}, // 1.0 - (-1.0) = 2.0
141+
{name: "-1.0 - 1.0", a: 0xBC00, b: 0x3C00, expect: 0xC000, hasError: false}, // -1.0 - 1.0 = -2.0
142+
{name: "0.0 - 0.0", a: 0x0000, b: 0x0000, expect: 0x0000, hasError: false}, // 0.0 - 0.0 = 0.0 (or -0.0 is also valid)
143+
{name: "Inf - 1.0", a: 0x7C00, b: 0x3C00, expect: 0x7C00, hasError: false}, // +Inf - 1.0 = +Inf
144+
{name: "1.0 - Inf", a: 0x3C00, b: 0x7C00, expect: 0xFC00, hasError: false}, // 1.0 - +Inf = -Inf
145+
{name: "NaN - 1.0", a: 0x7E00, b: 0x3C00, expect: 0x7E00, hasError: false}, // NaN - 1.0 = NaN
146+
{name: "1.0 - NaN", a: 0x3C00, b: 0x7E00, expect: 0x7E00, hasError: false}, // 1.0 - NaN = NaN
147+
}
148+
149+
for _, tt := range tests {
150+
t.Run(tt.name, func(t *testing.T) {
151+
result, err := SubWithMode(tt.a, tt.b, ModeIEEEArithmetic, RoundNearestEven)
152+
153+
if tt.hasError {
154+
if err == nil {
155+
t.Error("Expected error, got nil")
156+
}
157+
return
158+
}
159+
160+
if err != nil {
161+
t.Fatalf("Unexpected error: %v", err)
162+
}
163+
164+
// For 0.0 - 0.0, both 0.0 and -0.0 are valid results
165+
if tt.a == 0 && tt.b == 0 {
166+
// Check if the result is either 0.0 or -0.0
167+
if result != 0 && result != Float16(0x8000) {
168+
t.Errorf("SubWithMode(%v, %v) = %v (0x%04X), want 0.0 (0x0000) or -0.0 (0x8000)",
169+
tt.a, tt.b, result, uint16(result))
170+
}
171+
} else if result != tt.expect {
172+
t.Errorf("SubWithMode(%v, %v) = %v (0x%04X), want %v (0x%04X)",
173+
tt.a, tt.b, result, uint16(result), tt.expect, uint16(tt.expect))
174+
}
175+
})
176+
}
177+
}
178+
179+
func TestSub(t *testing.T) {
180+
tests := []struct {
181+
a Float16
182+
b Float16
183+
expect Float16
184+
}{
185+
{0x4200, 0x3C00, 0x4000}, // 3.0 - 1.0 = 2.0
186+
{0x3C00, 0x3C00, 0x0000}, // 1.0 - 1.0 = 0.0
187+
{0x3C00, 0x4000, 0xBC00}, // 1.0 - 2.0 = -1.0
188+
}
189+
190+
for _, tt := range tests {
191+
t.Run(tt.a.String()+" - "+tt.b.String(), func(t *testing.T) {
192+
result := Sub(tt.a, tt.b)
193+
if result != tt.expect {
194+
t.Errorf("Sub(%v, %v) = %v (0x%04X), want %v (0x%04X)",
195+
tt.a, tt.b, result, uint16(result), tt.expect, uint16(tt.expect))
196+
}
197+
})
198+
}
199+
}

0 commit comments

Comments
 (0)