Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

math/big: Float.{Add, Sub} allocate even when receiver does not alias the arguments #14868

Closed
ALTree opened this issue Mar 18, 2016 · 0 comments

Comments

@ALTree
Copy link
Member

ALTree commented Mar 18, 2016

Currently big.Float.Add and big.Float.Sub allocate even if none of the arguments alias the receiver. Code:

package benchAddSub

import (
    "math/big"
    "testing"
)

var prec uint = 1e5

var x *big.Float = new(big.Float).SetPrec(prec).SetUint64(2)
var y *big.Float = new(big.Float).SetPrec(prec)
var t *big.Float = new(big.Float).SetPrec(prec)

func init() {
    y.Parse("1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095523292304843087143214508397626036279952514079896872533965463318088296406206152583523950547457502877599617298355752203375318570113543746034084988471603868999706990048150305440277903164542478230684929369186215805784631115966687130130156185689872372352885092648612494977154218334204285686060146824720771435854874155657069677653720226485447015858801620758474922657226002085584466521458398893944370926591800311388246468157082630100594858704003186480342194897278290641045072636881313739855256117322040245091227700226941127573627280495738108967504018369868368450725799364729060762996941380475654823728997180326802474420629269124859052181004459842150591120249441341728531478105803603371077309182869314710171111683916581726889419758716582152128229518488472089694633862891562882765952635140542", 10)
}

func BenchmarkAddFloats(b *testing.B) {
    b.ReportAllocs()
    for i := 0; i < b.N; i++ {
        t.Add(x, y)
    }
}

func BenchmarkSubFloats(b *testing.B) {
    b.ReportAllocs()
    for i := 0; i < b.N; i++ {
        t.Sub(x, y)
    }
}

(playground http://play.golang.org/p/rNaj0NwPOT) gives

BenchmarkAddFloats-4      200000          6124 ns/op       13568 B/op          1 allocs/op
BenchmarkSubFloats-4      300000          5732 ns/op       13568 B/op          1 allocs/op

The relevant code (for Add) is here: https://github.com/golang/go/blob/master/src/math/big/float.go#L1229-L1242

Looks like it shouldn't be hard to fix, maybe something like

al := alias(z.mant, x.mant) || alias(z.mant, y.mant)

switch {
case ex < ey:
    if !al { // no aliasing, can re-use z
        z.mant = z.mant.shl(y.mant, uint(ey-ex))
        z.mant = z.mant.sub(x.mant, z.mant)
    } else {
        t := nat(nil).shl(y.mant, uint(ey-ex))
        z.mant = t.sub(x.mant, t)
    }
...
@griesemer griesemer self-assigned this Mar 18, 2016
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Mar 19, 2016
@golang golang locked and limited conversation to collaborators Aug 17, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants