Repository: shogo82148/floats
Pull request #53: Implement Quo method for Float256 and add corresponding tests
Author: login: shogo82148
Created: 2025-04-29T16:06:58Z | Merged: 2025-04-29T16:15:55Z

- https://github.com/shogo82148/floats/issues/33

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
	- Introduced division support for 256-bit floating point numbers, including handling of special cases such as zeros, infinities, and NaN values.
- **Tests**
	- Added comprehensive tests for the new division operation, covering normal and edge cases.
	- Added a benchmark to measure the performance of the division operation.
- **Chores**
	- Added a utility function for processing 512-bit values.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/float256.go b/float256.go
index 45e6f06..b90d9c9 100644
--- a/float256.go
+++ b/float256.go
@@ -146,6 +146,98 @@ func (a Float256) Mul(b Float256) Float256 {
 	}
 }
 
+// Quo returns the quotient of a and b.
+func (a Float256) Quo(b Float256) Float256 {
+	if a.IsNaN() {
+		return a
+	}
+	if b.IsNaN() {
+		return b
+	}
+
+	signA, expA, fracA := a.split()
+	signB, expB, fracB := b.split()
+	sign := signA ^ signB
+
+	if b.isZero() {
+		if a.isZero() {
+			// 0 / 0 = NaN
+			return Float256(uvnan256)
+		}
+		// ±finite / 0 = ±inf
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+	if a.isZero() {
+		// 0 / finite = 0
+		return Float256{sign, 0, 0, 0}
+	}
+	if expA == mask256-bias256 {
+		// NaN check is done above; a is ±inf
+		if expB == mask256-bias256 {
+			// ±inf / ±inf = NaN
+			return Float256(uvnan256)
+		}
+		// ±inf / finite = ±inf
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+	if expB == mask256-bias256 {
+		// NaN check is done above; b is ±inf
+		// NaN and Inf checks are done above; a is finite.
+		// ±finite / ±inf = 0
+		return Float256{sign, 0, 0, 0}
+	}
+
+	exp := expA - expB + bias256
+	if fracA.Cmp(fracB) < 0 {
+		exp--
+		fracA = fracA.Lsh(1)
+	}
+	if exp >= mask256 {
+		// overflow
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+
+	shift := shift256 + 3 // 1 for the implicit bit, 1 for the rounding bit, 1 for the guard bit
+	fracA512 := fracA.Uint512().Lsh(uint(shift))
+	fracB512 := fracB.Uint512()
+	frac512, mod := fracA512.DivMod(fracB512)
+	frac512[7] |= squash512(mod)
+	frac := frac512.Uint256()
+
+	one := ints.Uint256{0, 0, 0, 1}
+	if exp <= 0 {
+		// the result is subnormal
+		shift := -exp + 3 + 1
+		frac = frac.Add(one.Lsh(uint(shift - 1)).Sub(one)).Add(frac.Rsh(uint(shift)).And(one)) // round to nearest even
+		frac = frac.Rsh(uint(shift))
+		return Float256{
+			sign | frac[0],
+			frac[1],
+			frac[2],
+			frac[3],
+		}
+	}
+
+	// round-to-nearest-even (guard+round+sticky are in the low 3 bits)
+	frac = frac.Add(ints.Uint256{0, 0, 0, 0b11}).Add(frac.Rsh(3).And(one))
+	// detect carry-out caused by rounding
+	if frac.BitLen() > shift256+3+1 {
+		frac = frac.Rsh(1)
+		exp++
+		if exp >= mask256 {
+			// overflow
+			return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+		}
+	}
+	frac = frac.Rsh(3)
+	return Float256{
+		sign | uint64(exp)<<(shift256-192) | frac[0]&fracMask256[0],
+		frac[1],
+		frac[2],
+		frac[3],
+	}
+}
+
 func (a Float256) split() (sign uint64, exp int, frac ints.Uint256) {
 	b := ints.Uint256(a)
 	sign = b[0] & signMask256[0]
diff --git a/float256_test.go b/float256_test.go
index 09cc436..43b0025 100644
--- a/float256_test.go
+++ b/float256_test.go
@@ -564,3 +564,219 @@ func BenchmarkFloat256_Mul(b *testing.B) {
 		runtime.KeepAlive(f.Mul(f))
 	}
 }
+
+func TestFloat256_Quo(t *testing.T) {
+	tests := []struct {
+		a, b, want Float256
+	}{
+		{
+			// 1.0
+			a: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 1.0
+			b: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 1.0
+			want: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+
+		// zero division
+		{
+			// 1.0
+			a: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 0.0
+			b: Float256{
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// +Inf
+			want: Float256{
+				0x7fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+		{
+			// 0.0
+			a: Float256{
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 0.0
+			b: Float256{
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// NaN
+			want: Float256{
+				0x7fff_f800_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+
+		// handling NaN
+		{
+			// NaN
+			a: Float256{
+				0x7fff_f800_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 1.0
+			b: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// NaN
+			want: Float256{
+				0x7fff_f800_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+		{
+			// 1.0
+			a: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// NaN
+			b: Float256{
+				0x7fff_f800_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// NaN
+			want: Float256{
+				0x7fff_f800_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+
+		// handling infinity
+		{
+			// 1.0
+			a: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// inf
+			b: Float256{
+				0x7fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 0
+			want: Float256{
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+		{
+			// inf
+			a: Float256{
+				0x7fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// 1.0
+			b: Float256{
+				0x3fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// inf
+			want: Float256{
+				0x7fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+		{
+			// inf
+			a: Float256{
+				0x7fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// inf
+			b: Float256{
+				0x7fff_f000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+			// NaN
+			want: Float256{
+				0x7fff_f800_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+				0x0000_0000_0000_0000,
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		got := tt.a.Quo(tt.b)
+		if !eq256(got, tt.want) {
+			t.Errorf("Float256(%x).Quo(%x) = %x, want %x", tt.a, tt.b, got, tt.want)
+		}
+	}
+}
+
+func BenchmarkFloat256_Quo(b *testing.B) {
+	f := Float256{
+		0x3fff_f000_0000_0000,
+		0x0000_0000_0000_0000,
+		0x0000_0000_0000_0000,
+		0x0000_0000_0000_0000,
+	}
+	for b.Loop() {
+		runtime.KeepAlive(f.Quo(f))
+	}
+}
diff --git a/utils.go b/utils.go
index 1d4bb35..96496a3 100644
--- a/utils.go
+++ b/utils.go
@@ -33,3 +33,15 @@ func squash256(x ints.Uint256) uint64 {
 	y |= y >> 1
 	return y & 1
 }
+
+// squash512 squashes the bits of x to a single bit.
+func squash512(x ints.Uint512) uint64 {
+	y := x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7]
+	y |= y >> 32
+	y |= y >> 16
+	y |= y >> 8
+	y |= y >> 4
+	y |= y >> 2
+	y |= y >> 1
+	return y & 1
+}


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR implements the Quo method for the Float256 type and adds extensive tests to cover various edge cases including zero, NaN, and infinity scenarios. It also introduces a new utility function, squash512, to support the division rounding logic.
- Added squash512 helper in utils.go.
- Implemented Quo method in float256.go with comprehensive handling for special cases.
- Added tests for the Quo method in float256_test.go.

### Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

| File             | Description                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| utils.go         | Added squash512 utility for Uint512 rounding support.                   |
| float256.go      | Implemented the Quo method for Float256 with special case handling.     |
| float256_test.go | Added tests covering normal, zero, infinity, and NaN division scenarios.  |


<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**float256.go:200**
* [nitpick] Consider defining named constants for the magic numbers used in the rounding and shifting logic (e.g., for the implicit bit, rounding bit, and guard bit) to improve readability and maintainability.
```
shift := shift256 + 3 // 1 for the implicit bit, 1 for the rounding bit, 1 for the guard bit
```
**float256.go:222**
* [nitpick] Consider extracting the value 0b11 into a descriptively named constant that reflects its role in the rounding process to enhance code clarity.
```
frac = frac.Add(ints.Uint256{0, 0, 0, 0b11}).Add(frac.Rsh(3).And(one))
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T16:07:16Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>utils.go (1)</summary><blockquote>

`37-46`: **Consider eliminating duplication and future-proofing with a small loop.**

`squash512` duplicates the manual “cascade-or” pipeline we already have in `squash16`, `squash64`, and `squash256`.  
While the eight explicit `x[i]` ORs are inexpensive, they are easy to get wrong (e.g. when introducing `Uint1024`) and invite copy-paste drift.

A micro helper keeps all squashers one-liner-simple and makes the intent obvious:

```diff
-func squash512(x ints.Uint512) uint64 {
-	y := x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7]
-	y |= y >> 32
-	y |= y >> 16
-	y |= y >> 8
-	y |= y >> 4
-	y |= y >> 2
-	y |= y >> 1
-	return y & 1
-}
+func squash512(x ints.Uint512) uint64 {
+	var y uint64
+	for _, w := range x { // future-proof against length changes
+		y |= w
+	}
+	// propagate down to LSB
+	y |= y >> 32
+	y |= y >> 16
+	y |= y >> 8
+	y |= y >> 4
+	y |= y >> 2
+	y |= y >> 1
+	return y & 1
+}
```

No measurable perf impact is expected (branch-free, tiny loop unrolled by the compiler), but maintainability improves markedly.

</blockquote></details>
<details>
<summary>float256_test.go (1)</summary><blockquote>

`568-770`: **Good breadth, but key scenarios are still missing – extend test table.**

The new table covers zero, NaN and Inf well, yet the algorithm’s hardest parts remain untested:

1. Sub-normal result (very small numerator / normal denominator).  
2. Overflow (huge numerator / tiny denominator).  
3. Tie-to-even rounding where guard+round+sticky = `100`.  
4. Rounding carry-out path noted in float256.go ‑L225.

Adding 3-4 concise vectors will raise coverage for Codecov-flagged lines and lock correctness.  


I can draft the additional vectors if helpful.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 7f4d4a3cfb61afc9be1457e6f4fbcfd604fea9d1 and 0bc3eb65fbe8d8e5d35efbd73d59fd3810aa05cf.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `float256.go` (1 hunks)
* `float256_test.go` (1 hunks)
* `utils.go` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

<details>
<summary>float256.go</summary>

[warning] 171-173: float256.go#L171-L173
Added lines #L171 - L173 were not covered by tests

---

[warning] 192-194: float256.go#L192-L194
Added lines #L192 - L194 were not covered by tests

---

[warning] 196-198: float256.go#L196-L198
Added lines #L196 - L198 were not covered by tests

---

[warning] 209-219: float256.go#L209-L219
Added lines #L209 - L219 were not covered by tests

---

[warning] 225-230: float256.go#L225-L230
Added lines #L225 - L230 were not covered by tests

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>float256.go (2)</summary>

`150-169`: **Division-by-zero branch: sign handling looks correct – nice.**

The early return for `b.isZero()` resolves to ±Inf with `signA ^ signB`, fully mirroring IEEE-754 rules, and the `0/0` NaN case is covered immediately above.

---

`225-230`: **Carry-out path lacks test coverage – add an overflow-rounding case.**

`frac.BitLen() > shift256+3+1` is crucial when rounding pushes the mantissa over 2.  
None of the new `TestFloat256_Quo` vectors exercise this branch (see Codecov warnings).

Please add a case like `1.111… / 1.0` where guard+round+sticky cause a carry into the implicit bit, verifying both the rounded mantissa and the exponent increment.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 225-230: float256.go#L225-L230
Added lines #L225 - L230 were not covered by tests

</details>

</details>

</details>
<details>
<summary>float256_test.go (1)</summary>

`772-782`: **Benchmark uses `b.Loop()` – verify Go version compatibility.**

`testing.B` gained `Loop` only in Go 1.22+.  
If the library targets earlier releases, replace with the canonical `for i := 0; i < b.N; i++ { … }` loop to avoid build failures for downstream users.

```diff
-for b.Loop() {
-	runtime.KeepAlive(f.Quo(f))
-}
+for i := 0; i < b.N; i++ {
+	runtime.KeepAlive(f.Quo(f))
+}
```

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T16:13:56Z

Review comments:
diff_hunk: @@ -146,6 +146,98 @@
 	}
 }
 
+// Quo returns the quotient of a and b.
+func (a Float256) Quo(b Float256) Float256 {
+	if a.IsNaN() {
+		return a
+	}
+	if b.IsNaN() {
+		return b
+	}
+
+	signA, expA, fracA := a.split()
+	signB, expB, fracB := b.split()
+	sign := signA ^ signB
+
+	if b.isZero() {
+		if a.isZero() {
+			// 0 / 0 = NaN
+			return Float256(uvnan256)
+		}
+		// ±finite / 0 = ±inf
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+	if a.isZero() {
+		// 0 / finite = 0
+		return Float256{sign, 0, 0, 0}
+	}
+	if expA == mask256-bias256 {
+		// NaN check is done above; a is ±inf
+		if expB == mask256-bias256 {
+			// ±inf / ±inf = NaN
+			return Float256(uvnan256)
+		}
+		// ±inf / finite = ±inf
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+	if expB == mask256-bias256 {
+		// NaN check is done above; b is ±inf
+		// NaN and Inf checks are done above; a is finite.
+		// ±finite / ±inf = 0
+		return Float256{sign, 0, 0, 0}
+	}
+
+	exp := expA - expB + bias256
+	if fracA.Cmp(fracB) < 0 {
+		exp--
+		fracA = fracA.Lsh(1)
+	}
+	if exp >= mask256 {
+		// overflow
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+
+	shift := shift256 + 3 // 1 for the implicit bit, 1 for the rounding bit, 1 for the guard bit
+	fracA512 := fracA.Uint512().Lsh(uint(shift))
+	fracB512 := fracB.Uint512()
+	frac512, mod := fracA512.DivMod(fracB512)
+	frac512[7] |= squash512(mod)
+	frac := frac512.Uint256()
+
+	one := ints.Uint256{0, 0, 0, 1}
+	if exp <= 0 {
+		// the result is subnormal
+		shift := -exp + 3 + 1
+		frac = frac.Add(one.Lsh(uint(shift - 1)).Sub(one)).Add(frac.Rsh(uint(shift)).And(one)) // round to nearest even
+		frac = frac.Rsh(uint(shift))
+		return Float256{
+			sign | frac[0],
+			frac[1],
+			frac[2],
+			frac[3],
+		}
path: float256.go
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Possible exponent bits leakage when returning a sub-normal result.**

`frac[0]` may contain bits in the exponent field position (bit 236) after rounding, but sub-normal encodings require all exponent bits to be **zero**.  
Currently:

```go
return Float256{
	sign | frac[0],  // <-- potential leakage
	frac[1], frac[2], frac[3],
}
```

Masking with `fracMask256[0]` avoids accidentally creating a pseudo-normal number:

```diff
-			sign | frac[0],
+			sign | (frac[0] & fracMask256[0]),
```

Please double-check downstream uses (e.g. `BitLen()` checks) once this mask is applied.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T16:13:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -146,6 +146,98 @@
 	}
 }
 
+// Quo returns the quotient of a and b.
+func (a Float256) Quo(b Float256) Float256 {
+	if a.IsNaN() {
+		return a
+	}
+	if b.IsNaN() {
+		return b
+	}
+
+	signA, expA, fracA := a.split()
+	signB, expB, fracB := b.split()
+	sign := signA ^ signB
+
+	if b.isZero() {
+		if a.isZero() {
+			// 0 / 0 = NaN
+			return Float256(uvnan256)
+		}
+		// ±finite / 0 = ±inf
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+	if a.isZero() {
+		// 0 / finite = 0
+		return Float256{sign, 0, 0, 0}
+	}
+	if expA == mask256-bias256 {
+		// NaN check is done above; a is ±inf
+		if expB == mask256-bias256 {
+			// ±inf / ±inf = NaN
+			return Float256(uvnan256)
+		}
+		// ±inf / finite = ±inf
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+	if expB == mask256-bias256 {
+		// NaN check is done above; b is ±inf
+		// NaN and Inf checks are done above; a is finite.
+		// ±finite / ±inf = 0
+		return Float256{sign, 0, 0, 0}
+	}
+
+	exp := expA - expB + bias256
+	if fracA.Cmp(fracB) < 0 {
+		exp--
+		fracA = fracA.Lsh(1)
+	}
+	if exp >= mask256 {
+		// overflow
+		return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+	}
+
+	shift := shift256 + 3 // 1 for the implicit bit, 1 for the rounding bit, 1 for the guard bit
+	fracA512 := fracA.Uint512().Lsh(uint(shift))
+	fracB512 := fracB.Uint512()
+	frac512, mod := fracA512.DivMod(fracB512)
+	frac512[7] |= squash512(mod)
+	frac := frac512.Uint256()
+
+	one := ints.Uint256{0, 0, 0, 1}
+	if exp <= 0 {
+		// the result is subnormal
+		shift := -exp + 3 + 1
+		frac = frac.Add(one.Lsh(uint(shift - 1)).Sub(one)).Add(frac.Rsh(uint(shift)).And(one)) // round to nearest even
+		frac = frac.Rsh(uint(shift))
+		return Float256{
+			sign | frac[0],
+			frac[1],
+			frac[2],
+			frac[3],
+		}
+	}
+
+	// round-to-nearest-even (guard+round+sticky are in the low 3 bits)
+	frac = frac.Add(ints.Uint256{0, 0, 0, 0b11}).Add(frac.Rsh(3).And(one))
+	// detect carry-out caused by rounding
+	if frac.BitLen() > shift256+3+1 {
+		frac = frac.Rsh(1)
+		exp++
+		if exp >= mask256 {
+			// overflow
+			return Float256{sign | uvinf256[0], uvinf256[1], uvinf256[2], uvinf256[3]}
+		}
+	}
+	frac = frac.Rsh(3)
+	return Float256{
path: float256.go
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Rounding constant omits the guard bit – tie-to-even may be off by one.**

The quotient keeps guard, round and sticky bits in **three** LSBs (comment line 221) yet the constant adds only the two low bits (`0b11`).  
To achieve “+½ ulps then clear”, the guard bit (bit 2) must be considered as well:

```diff
-	frac = frac.Add(ints.Uint256{0, 0, 0, 0b11}).Add(frac.Rsh(3).And(one))
+	frac = frac.Add(ints.Uint256{0, 0, 0, 0b111}).Add(frac.Rsh(3).And(one))
```

Without this, results exactly halfway between representable values will round **down** instead of to nearest-even.  



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
	// round-to-nearest-even (guard+round+sticky are in the low 3 bits)
	frac = frac.Add(ints.Uint256{0, 0, 0, 0b111}).Add(frac.Rsh(3).And(one))
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 225-230: float256.go#L225-L230
Added lines #L225 - L230 were not covered by tests

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-29T16:13:56Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-29T16:07:04Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

A new division method `Quo` was implemented for the `Float256` type, providing IEEE 754-compliant floating-point division with detailed handling of special cases such as NaN, infinity, and zero. Supporting this, a utility function `squash512` was introduced to condense 512-bit values to a single bit. Corresponding unit tests and benchmarks for the new division method were added, covering various scenarios including normal division, edge cases, and performance measurement.

## Changes

| File(s)                                | Change Summary                                                                                                    |
|-----------------------------------------|------------------------------------------------------------------------------------------------------------------|
| float256.go                            | Added the `Quo` method to `Float256` for IEEE 754-compliant division, handling special cases and rounding.       |
| float256_test.go                       | Introduced `TestFloat256_Quo` for unit testing division, and `BenchmarkFloat256_Quo` for performance benchmarking.|
| utils.go                               | Added the `squash512` function to reduce a 512-bit value to a single bit.                                        |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant A as Float256 (a)
    participant B as Float256 (b)
    participant U as squash512
    participant R as Result (Float256)
    A->>B: Quo(b)
    B-->>A: Provide sign, exponent, fraction
    A->>A: Handle NaN, zero, infinity cases
    A->>U: squash512(fraction data)
    U-->>A: Single bit result
    A->>A: Perform 512-bit division, rounding, normalization
    A->>R: Construct result Float256
    R-->>A: Return result
```

## Poem

> In the realm of bits, division’s here,  
> Float256 now splits without fear.  
> Special cases handled with care,  
> Infinity, NaN, and zeros rare.  
> With squash512 lending a bit,  
> Tests and benchmarks prove it’s legit!  
> 🐇✨ Divide and delight, the code is just right!

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=shogo82148/floats&utm_content=53):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-04-29T16:07:29Z
body: ## [Codecov](https://app.codecov.io/gh/shogo82148/floats/pull/53?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo) Report
Attention: Patch coverage is `64.77273%` with `31 lines` in your changes missing coverage. Please review.
> Project coverage is 55.78%. Comparing base [(`7f4d4a3`)](https://app.codecov.io/gh/shogo82148/floats/commit/7f4d4a3cfb61afc9be1457e6f4fbcfd604fea9d1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo) to head [(`0bc3eb6`)](https://app.codecov.io/gh/shogo82148/floats/commit/0bc3eb65fbe8d8e5d35efbd73d59fd3810aa05cf?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo).

| [Files with missing lines](https://app.codecov.io/gh/shogo82148/floats/pull/53?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo) | Patch % | Lines |
|---|---|---|
| [float256.go](https://app.codecov.io/gh/shogo82148/floats/pull/53?src=pr&el=tree&filepath=float256.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo#diff-ZmxvYXQyNTYuZ28=) | 60.75% | [26 Missing and 5 partials :warning: ](https://app.codecov.io/gh/shogo82148/floats/pull/53?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main      #53      +/-   ##
==========================================
+ Coverage   55.35%   55.78%   +0.43%     
==========================================
  Files           8        8              
  Lines        1830     1918      +88     
==========================================
+ Hits         1013     1070      +57     
- Misses        812      838      +26     
- Partials        5       10       +5     
```

| [Flag](https://app.codecov.io/gh/shogo82148/floats/pull/53/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo) | Coverage Δ | |
|---|---|---|
| [1.24](https://app.codecov.io/gh/shogo82148/floats/pull/53/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo) | `55.78% <64.77%> (+0.43%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/shogo82148/floats/pull/53?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ICHINOSE+Shogo).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE