Skip to content

Commit cda633b

Browse files
ALTreegriesemer
authored andcommitted
math/big: avoid allocation in float.{Add, Sub} when there's no aliasing
name old time/op new time/op delta FloatAdd/10-4 116ns ± 1% 82ns ± 0% -28.74% (p=0.008 n=5+5) FloatAdd/100-4 124ns ± 0% 86ns ± 1% -30.34% (p=0.016 n=4+5) FloatAdd/1000-4 192ns ± 1% 123ns ± 0% -35.94% (p=0.008 n=5+5) FloatAdd/10000-4 826ns ± 0% 438ns ± 0% -46.99% (p=0.000 n=4+5) FloatAdd/100000-4 6.82µs ± 1% 3.36µs ± 0% -50.74% (p=0.008 n=5+5) FloatSub/10-4 108ns ± 1% 77ns ± 1% -29.06% (p=0.008 n=5+5) FloatSub/100-4 115ns ± 0% 79ns ± 0% -31.48% (p=0.029 n=4+4) FloatSub/1000-4 168ns ± 0% 99ns ± 0% -41.09% (p=0.029 n=4+4) FloatSub/10000-4 690ns ± 2% 288ns ± 1% -58.24% (p=0.008 n=5+5) FloatSub/100000-4 5.37µs ± 1% 2.10µs ± 1% -60.89% (p=0.008 n=5+5) name old alloc/op new alloc/op delta FloatAdd/10-4 48.0B ± 0% 0.0B ±NaN% -100.00% (p=0.008 n=5+5) FloatAdd/100-4 64.0B ± 0% 0.0B ±NaN% -100.00% (p=0.008 n=5+5) FloatAdd/1000-4 176B ± 0% 0B ±NaN% -100.00% (p=0.008 n=5+5) FloatAdd/10000-4 1.41kB ± 0% 0.00kB ±NaN% -100.00% (p=0.008 n=5+5) FloatAdd/100000-4 13.6kB ± 0% 0.0kB ±NaN% -100.00% (p=0.008 n=5+5) FloatSub/10-4 48.0B ± 0% 0.0B ±NaN% -100.00% (p=0.008 n=5+5) FloatSub/100-4 64.0B ± 0% 0.0B ±NaN% -100.00% (p=0.008 n=5+5) FloatSub/1000-4 176B ± 0% 0B ±NaN% -100.00% (p=0.008 n=5+5) FloatSub/10000-4 1.41kB ± 0% 0.00kB ±NaN% -100.00% (p=0.008 n=5+5) FloatSub/100000-4 13.6kB ± 0% 0.0kB ±NaN% -100.00% (p=0.008 n=5+5) Fixes #14868 Change-Id: Ia2b8b1a8ef0868288ecb25f812b17bd03ff40d1c Reviewed-on: https://go-review.googlesource.com/23568 Reviewed-by: Robert Griesemer <[email protected]>
1 parent f542576 commit cda633b

File tree

2 files changed

+70
-12
lines changed

2 files changed

+70
-12
lines changed

src/math/big/float.go

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,20 +1210,30 @@ func (z *Float) uadd(x, y *Float) {
12101210
ex := int64(x.exp) - int64(len(x.mant))*_W
12111211
ey := int64(y.exp) - int64(len(y.mant))*_W
12121212

1213+
al := alias(z.mant, x.mant) || alias(z.mant, y.mant)
1214+
12131215
// TODO(gri) having a combined add-and-shift primitive
12141216
// could make this code significantly faster
12151217
switch {
12161218
case ex < ey:
1217-
// cannot re-use z.mant w/o testing for aliasing
1218-
t := nat(nil).shl(y.mant, uint(ey-ex))
1219-
z.mant = z.mant.add(x.mant, t)
1219+
if al {
1220+
t := nat(nil).shl(y.mant, uint(ey-ex))
1221+
z.mant = z.mant.add(x.mant, t)
1222+
} else {
1223+
z.mant = z.mant.shl(y.mant, uint(ey-ex))
1224+
z.mant = z.mant.add(x.mant, z.mant)
1225+
}
12201226
default:
12211227
// ex == ey, no shift needed
12221228
z.mant = z.mant.add(x.mant, y.mant)
12231229
case ex > ey:
1224-
// cannot re-use z.mant w/o testing for aliasing
1225-
t := nat(nil).shl(x.mant, uint(ex-ey))
1226-
z.mant = z.mant.add(t, y.mant)
1230+
if al {
1231+
t := nat(nil).shl(x.mant, uint(ex-ey))
1232+
z.mant = z.mant.add(t, y.mant)
1233+
} else {
1234+
z.mant = z.mant.shl(x.mant, uint(ex-ey))
1235+
z.mant = z.mant.add(z.mant, y.mant)
1236+
}
12271237
ex = ey
12281238
}
12291239
// len(z.mant) > 0
@@ -1247,18 +1257,28 @@ func (z *Float) usub(x, y *Float) {
12471257
ex := int64(x.exp) - int64(len(x.mant))*_W
12481258
ey := int64(y.exp) - int64(len(y.mant))*_W
12491259

1260+
al := alias(z.mant, x.mant) || alias(z.mant, y.mant)
1261+
12501262
switch {
12511263
case ex < ey:
1252-
// cannot re-use z.mant w/o testing for aliasing
1253-
t := nat(nil).shl(y.mant, uint(ey-ex))
1254-
z.mant = t.sub(x.mant, t)
1264+
if al {
1265+
t := nat(nil).shl(y.mant, uint(ey-ex))
1266+
z.mant = t.sub(x.mant, t)
1267+
} else {
1268+
z.mant = z.mant.shl(y.mant, uint(ey-ex))
1269+
z.mant = z.mant.sub(x.mant, z.mant)
1270+
}
12551271
default:
12561272
// ex == ey, no shift needed
12571273
z.mant = z.mant.sub(x.mant, y.mant)
12581274
case ex > ey:
1259-
// cannot re-use z.mant w/o testing for aliasing
1260-
t := nat(nil).shl(x.mant, uint(ex-ey))
1261-
z.mant = t.sub(t, y.mant)
1275+
if al {
1276+
t := nat(nil).shl(x.mant, uint(ex-ey))
1277+
z.mant = t.sub(t, y.mant)
1278+
} else {
1279+
z.mant = z.mant.shl(x.mant, uint(ex-ey))
1280+
z.mant = z.mant.sub(z.mant, y.mant)
1281+
}
12621282
ex = ey
12631283
}
12641284

src/math/big/float_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,3 +1762,41 @@ func TestFloatCmpSpecialValues(t *testing.T) {
17621762
}
17631763
}
17641764
}
1765+
1766+
func BenchmarkFloatAdd(b *testing.B) {
1767+
x := new(Float)
1768+
y := new(Float)
1769+
z := new(Float)
1770+
1771+
for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} {
1772+
x.SetPrec(prec).SetRat(NewRat(1, 3))
1773+
y.SetPrec(prec).SetRat(NewRat(1, 6))
1774+
z.SetPrec(prec)
1775+
1776+
b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
1777+
b.ReportAllocs()
1778+
for i := 0; i < b.N; i++ {
1779+
z.Add(x, y)
1780+
}
1781+
})
1782+
}
1783+
}
1784+
1785+
func BenchmarkFloatSub(b *testing.B) {
1786+
x := new(Float)
1787+
y := new(Float)
1788+
z := new(Float)
1789+
1790+
for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} {
1791+
x.SetPrec(prec).SetRat(NewRat(1, 3))
1792+
y.SetPrec(prec).SetRat(NewRat(1, 6))
1793+
z.SetPrec(prec)
1794+
1795+
b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
1796+
b.ReportAllocs()
1797+
for i := 0; i < b.N; i++ {
1798+
z.Sub(x, y)
1799+
}
1800+
})
1801+
}
1802+
}

0 commit comments

Comments
 (0)