Skip to content

Commit 6c6e003

Browse files
authored
Merge pull request #3 from txaty/refactor/code-quality-enhancement
feat: Code tidy up, and performance improvements.
2 parents d79196f + 80e0f97 commit 6c6e003

File tree

5 files changed

+176
-158
lines changed

5 files changed

+176
-158
lines changed

README.md

+22-26
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,21 @@
66
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/f149e51e0475464d843477adba68b577)](https://app.codacy.com/gh/txaty/go-bigcomplex/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
77
[![MIT license](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
88

9-
Big complex number calculation library for Go (with [math/big](https://pkg.go.dev/math/big)).
9+
Big complex number calculation library in Go (with [math/big](https://pkg.go.dev/math/big)).
1010

1111
Currently, the library supports:
1212

13-
1. Gaussian integer, complex numbers whose real and imaginary parts are both integers:
13+
1. **Gaussian Integers**
14+
Complex numbers whose real and imaginary parts are both integers:
15+
$$
16+
\mathbb{Z}[i] = \{ a + bi \mid a, b \in \mathbb{Z} \}, \quad \text{where } i^2 = -1.
17+
$$
1418

15-
$$
16-
Z[i] = \{ a + bi \ |\ a, b \in \mathbb{Z} \}, \quad \text{where } i^2 = -1.
17-
$$
18-
19-
2. Hurwitz quaternion, quaternions whose components are either all integers or all half-integers (halves of odd
20-
integers; a mixture of integers and half-integers is excluded):
21-
22-
$$
23-
H = \{ a + bi + cj + dk \in \mathbb{H} \ |\ a, b, c, d \in \mathbb{Z} \ \text{or} \ b, c, d \in \mathbb{Z} + \frac{1}{2} \}.
24-
$$
19+
2. **Hurwitz Quaternions**
20+
Quaternions whose components are either all integers or all half‑integers (half‑integers being halves of odd integers; mixing integers and half‑integers is not allowed):
21+
$$
22+
H = \{ a + bi + cj + dk \in \mathbb{H} \mid a, b, c, d \in \mathbb{Z} \text{ or } a, b, c, d \in \mathbb{Z} + \tfrac{1}{2} \}.
23+
$$
2524

2625
## Installation
2726

@@ -64,24 +63,21 @@ func main() {
6463

6564
## Why This Library?
6665

67-
Fan fact: Golang has native complex number types: ```complex64``` and ```complex128```.
66+
Fan fact: Golang has native complex number types: `complex64` and `complex128`.
6867

6968
```go
70-
c1 := complex(10, 11) // constructor init
71-
c2 := 10 + 11i // complex number init syntax
69+
c1 := complex(10, 11) // Using the complex constructor
70+
c2 := 10 + 11i // Using literal syntax
7271
73-
realPart := real(c1) // gets real part
74-
imagPart := imag(c1) // gets imaginary part
72+
realPart := real(c1) // Retrieves the real part
73+
imagPart := imag(c1) // Retrieves the imaginary part
7574
```
7675

77-
```complex64``` represents ```float64``` real and imaginary data, and ```complex128``` represents ```float128``` real
78-
and imaginary data.
79-
They are easy to use, but unfortunately they are incapable for handling very large complex numbers.
76+
However, `complex64` (composed of two `float32` values) and `complex128` (composed of two `float64` values) are limited to fixed‑precision arithmetic and cannot handle very large numbers.
77+
For example, in finding the Lagrange Four Square Sum of a very large integer (1792 bits in size) for cryptographic range proof, we need to compute the Greatest Common Divisor (GCD) of Gaussian integers and the Greatest Common Right Divisor of Hurwitz integers. And the built-in complex number types cannot handle such large numbers.
78+
79+
This motivated the development of Big Complex: a library for large‑scale complex number calculations using Go’s math/big package.
8080

81-
For instance, in finding the Lagrange Four Square Sum of a very large integer (1792 bits in size) for cryptographic
82-
range proof,
83-
we need to compute the Greatest Common Divisor (GCD) of Gaussian integers and the Greatest Common Right Divisor of
84-
Hurwitz integers. And the built-in complex number types can not handle such large numbers.
81+
## License
8582

86-
So I came up with the idea of building a library for large complex number calculation with Golang ```math/big```
87-
package.
83+
This project is licensed under the MIT License.

constant.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ package complex
2525
import "math/big"
2626

2727
const (
28-
// the delta added or subtracted to round big floats to the nearest integers
28+
// The delta added or subtracted to round big floats to the nearest integers.
2929
roundingDelta = 0.49
3030
)
3131

3232
var (
33-
// big integer
33+
// Big integers.
3434
big1 = big.NewInt(1)
3535
bigNeg1 = big.NewInt(-1)
3636
big2 = big.NewInt(2)
3737

38-
// big float
38+
// Big floats.
3939
big2f = big.NewFloat(2)
4040

41-
// delta for rounding big float to big int
41+
// Delta for rounding big float to big int.
4242
rDelta = big.NewFloat(roundingDelta)
4343
)

gaussian_integer.go

+49-44
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ import (
2626
"math/big"
2727
)
2828

29-
// GaussianInt implements Gaussian integer
30-
// In number theory, a Gaussian integer is a complex number whose real and imaginary parts are both integers
29+
// GaussianInt represents a Gaussian integer, that is, a complex number
30+
// whose real and imaginary parts are both integers.
3131
type GaussianInt struct {
32-
R *big.Int // real part
33-
I *big.Int // imaginary part
32+
R *big.Int // Real part
33+
I *big.Int // Imaginary part
3434
}
3535

36-
// String returns the string representation of the Gaussian integer
36+
// String returns the string representation of the Gaussian integer.
3737
func (g *GaussianInt) String() string {
3838
rSign := g.R.Sign()
3939
iSign := g.I.Sign()
@@ -59,15 +59,15 @@ func (g *GaussianInt) String() string {
5959
return res
6060
}
6161

62-
// NewGaussianInt declares a new Gaussian integer with the real part and imaginary part
62+
// NewGaussianInt creates a new Gaussian integer with the specified real and imaginary parts.
6363
func NewGaussianInt(r *big.Int, i *big.Int) *GaussianInt {
6464
return &GaussianInt{
6565
R: new(big.Int).Set(r),
6666
I: new(big.Int).Set(i),
6767
}
6868
}
6969

70-
// Set sets the Gaussian integer to the given Gaussian integer
70+
// Set assigns the value of another Gaussian integer to this one.
7171
func (g *GaussianInt) Set(a *GaussianInt) *GaussianInt {
7272
if g.R == nil {
7373
g.R = new(big.Int)
@@ -80,7 +80,7 @@ func (g *GaussianInt) Set(a *GaussianInt) *GaussianInt {
8080
return g
8181
}
8282

83-
// Update updates the Gaussian integer with the given real and imaginary parts
83+
// Update sets the real and imaginary parts of the Gaussian integer.
8484
func (g *GaussianInt) Update(r, i *big.Int) *GaussianInt {
8585
if g.R == nil {
8686
g.R = new(big.Int)
@@ -93,7 +93,7 @@ func (g *GaussianInt) Update(r, i *big.Int) *GaussianInt {
9393
return g
9494
}
9595

96-
// Add adds two Gaussian integers
96+
// Add computes the sum of two Gaussian integers and stores the result in the receiver.
9797
func (g *GaussianInt) Add(a, b *GaussianInt) *GaussianInt {
9898
if g.R == nil {
9999
g.R = new(big.Int)
@@ -106,7 +106,7 @@ func (g *GaussianInt) Add(a, b *GaussianInt) *GaussianInt {
106106
return g
107107
}
108108

109-
// Sub subtracts two Gaussian integers
109+
// Sub subtracts one Gaussian integer from another and stores the result in the receiver.
110110
func (g *GaussianInt) Sub(a, b *GaussianInt) *GaussianInt {
111111
if g.R == nil {
112112
g.R = new(big.Int)
@@ -119,8 +119,10 @@ func (g *GaussianInt) Sub(a, b *GaussianInt) *GaussianInt {
119119
return g
120120
}
121121

122-
// Prod returns the products of two Gaussian integers
122+
// Prod calculates the product of two Gaussian integers and stores the result in the receiver.
123123
func (g *GaussianInt) Prod(a, b *GaussianInt) *GaussianInt {
124+
// Compute: (a.R + a.I*i) * (b.R + b.I*i)
125+
// = (a.R*b.R - a.I*b.I) + (a.R*b.I + a.I*b.R)*i
124126
r := new(big.Int).Mul(a.R, b.R)
125127
opt := iPool.Get().(*big.Int)
126128
defer iPool.Put(opt)
@@ -131,101 +133,104 @@ func (g *GaussianInt) Prod(a, b *GaussianInt) *GaussianInt {
131133
return g
132134
}
133135

134-
// Conj obtains the conjugate of the original Gaussian integer
136+
// Conj computes the conjugate of the given Gaussian integer and stores it in the receiver.
135137
func (g *GaussianInt) Conj(origin *GaussianInt) *GaussianInt {
138+
// The conjugate of (R + I*i) is (R - I*i).
136139
img := new(big.Int).Neg(origin.I)
137140
g.Update(origin.R, img)
138141
return g
139142
}
140143

141-
// Norm obtains the norm of the Gaussian integer
144+
// Norm returns the norm of the Gaussian integer (R^2 + I^2).
142145
func (g *GaussianInt) Norm() *big.Int {
143146
norm := new(big.Int).Mul(g.R, g.R)
144-
opt := iPool.Get().(*big.Int).Mul(g.I, g.I)
147+
opt := iPool.Get().(*big.Int)
145148
defer iPool.Put(opt)
149+
opt.Mul(g.I, g.I)
146150
norm.Add(norm, opt)
147151
return norm
148152
}
149153

150-
// Copy copies the Gaussian integer
154+
// Copy creates a deep copy of the Gaussian integer.
151155
func (g *GaussianInt) Copy() *GaussianInt {
152156
return NewGaussianInt(
153157
new(big.Int).Set(g.R),
154158
new(big.Int).Set(g.I),
155159
)
156160
}
157161

158-
// Div performs Euclidean division of two Gaussian integers, i.e. a/b
159-
// the remainder is stored in the Gaussian integer that calls the method
160-
// the quotient is returned as a new Gaussian integer
162+
// Div performs Euclidean division of two Gaussian integers (a / b).
163+
// The remainder is stored in the receiver, and the quotient is returned as a new Gaussian integer.
161164
func (g *GaussianInt) Div(a, b *GaussianInt) *GaussianInt {
162-
bConj := giPool.Get().(*GaussianInt).Conj(b)
163-
defer giPool.Put(bConj)
164-
numerator := giPool.Get().(*GaussianInt).Prod(a, bConj)
165-
defer giPool.Put(numerator)
166-
denominator := giPool.Get().(*GaussianInt).Prod(b, bConj)
167-
defer giPool.Put(denominator)
165+
// Compute the conjugate of b.
166+
bConj := new(GaussianInt).Conj(b)
167+
// Numerator = a * conjugate(b)
168+
numerator := new(GaussianInt).Prod(a, bConj)
169+
// Denominator = b * conjugate(b)
170+
denominator := new(GaussianInt).Prod(b, bConj)
171+
// Use the real part of the denominator for the division.
168172
deFloat := fPool.Get().(*big.Float).SetInt(denominator.R)
169173
defer fPool.Put(deFloat)
170174

175+
// Compute the real quotient component.
171176
realScalar := fPool.Get().(*big.Float).SetInt(numerator.R)
172177
defer fPool.Put(realScalar)
173178
realScalar.Quo(realScalar, deFloat)
174-
imagScalar := fPool.Get().(*big.Float).SetInt(numerator.I)
175-
defer fPool.Put(imagScalar)
176-
imagScalar.Quo(imagScalar, deFloat)
179+
// Compute the imaginary quotient component.
180+
imgScalar := fPool.Get().(*big.Float).SetInt(numerator.I)
181+
defer fPool.Put(imgScalar)
182+
imgScalar.Quo(imgScalar, deFloat)
177183

184+
// Round the computed float values to the nearest integers.
178185
rsInt := iPool.Get().(*big.Int)
179186
defer iPool.Put(rsInt)
180187
rsInt = roundFloat(realScalar)
181188
isInt := iPool.Get().(*big.Int)
182189
defer iPool.Put(isInt)
183-
isInt = roundFloat(imagScalar)
190+
isInt = roundFloat(imgScalar)
184191
quotient := NewGaussianInt(rsInt, isInt)
185-
opt := giPool.Get().(*GaussianInt)
186-
defer giPool.Put(opt)
187-
g.Sub(a, opt.Prod(quotient, b))
192+
193+
// Compute the remainder: remainder = a - (quotient * b)
194+
opt := new(GaussianInt).Prod(quotient, b)
195+
g.Sub(a, opt)
188196
return quotient
189197
}
190198

191-
// Equals checks if two Gaussian integers are equal
199+
// Equals returns true if the Gaussian integer is equal to the given Gaussian integer.
192200
func (g *GaussianInt) Equals(a *GaussianInt) bool {
193201
return g.R.Cmp(a.R) == 0 && g.I.Cmp(a.I) == 0
194202
}
195203

196-
// IsZero returns true if the Gaussian integer is equal to zero
204+
// IsZero returns true if the Gaussian integer is zero.
197205
func (g *GaussianInt) IsZero() bool {
198206
return g.R.Sign() == 0 && g.I.Sign() == 0
199207
}
200208

201-
// IsOne returns true if the Gaussian integer is equal to one
209+
// IsOne returns true if the Gaussian integer equals one.
202210
func (g *GaussianInt) IsOne() bool {
203211
return g.R.Sign() == 1 && g.I.Sign() == 0
204212
}
205213

206-
// CmpNorm compares the norm of two Gaussian integers
214+
// CmpNorm compares the norms of two Gaussian integers.
207215
func (g *GaussianInt) CmpNorm(a *GaussianInt) int {
208216
return g.Norm().Cmp(a.Norm())
209217
}
210218

211-
// GCD calculates the greatest common divisor of two Gaussian integers using Euclidean algorithm
212-
// the result is stored in the Gaussian integer that calls the method and returned
219+
// GCD calculates the greatest common divisor of two Gaussian integers using the Euclidean algorithm.
220+
// The result is stored in the receiver and also returned as a new Gaussian integer.
213221
func (g *GaussianInt) GCD(a, b *GaussianInt) *GaussianInt {
214-
ac := giPool.Get().(*GaussianInt).Set(a)
215-
defer giPool.Put(ac)
216-
bc := giPool.Get().(*GaussianInt).Set(b)
217-
defer giPool.Put(bc)
222+
ac := new(GaussianInt).Set(a)
223+
bc := new(GaussianInt).Set(b)
218224

219225
if ac.CmpNorm(bc) < 0 {
220226
ac, bc = bc, ac
221227
}
222-
remainder := giPool.Get().(*GaussianInt)
223-
defer giPool.Put(remainder)
228+
remainder := new(GaussianInt)
224229
for {
225230
remainder.Div(ac, bc)
226231
if remainder.IsZero() {
227232
g.Set(bc)
228-
return new(GaussianInt).Set(bc)
233+
return NewGaussianInt(bc.R, bc.I)
229234
}
230235
ac.Set(bc)
231236
bc.Set(remainder)

0 commit comments

Comments
 (0)