Skip to content

Commit

Permalink
ivy: add fast path for printing huge floats
Browse files Browse the repository at this point in the history
Work around Go issue golang/go#11068

It won't run if you've set a custom format - maybe we can handle
that in another round - but it makes a huge difference.

Big ints are unaffected.
  • Loading branch information
robpike committed Jun 23, 2015
1 parent 429013d commit 522bdae
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
73 changes: 73 additions & 0 deletions value/bigfloat.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package value

import (
"errors"
"fmt"
"math/big"
)

Expand All @@ -29,8 +30,80 @@ func setBigFloatString(s string) (BigFloat, error) {
return BigFloat{f}, nil
}

const fastFloatPrint = true

func (f BigFloat) String() string {
var mant big.Float
exp := f.Float.MantExp(&mant)
positive := 1
if exp < 0 {
positive = 0
exp = -exp
}
format := conf.Format()
// Printing huge floats can be very slow using
// big.Float's native methods; see issue #11068.
// For example 1e5000000 takes a minute of CPU time just
// to print. The code below is instantaneous, by rescaling
// first. It is however less feature-complete.
// (Big ints are problematic too, but if you print 1e50000000
// as an integer you probably won't be surprised it's slow.)
// TODO: Handle formats. Better yet, don't need this code.
if fastFloatPrint && exp > 10000 && (format == "" || format == "%v" || format == "%g") {
fexp := newF().SetInt64(int64(exp))
fexp.Mul(fexp, floatLog2)
fexp.Quo(fexp, floatLog10)
// We now have a floating-point base 10 exponent.
// Break into the integer part and the fractional part.
// The integer part is what we will show.
// The 10**(fractional part) will be multiplied back in.
iexp, _ := fexp.Int(nil)
fraction := fexp.Sub(fexp, newF().SetInt(iexp))
// Now compute 10**(fractional part).
// Fraction is in base 10. Move it to base e.
fraction.Mul(fraction, floatLog10)
scale := exponential(fraction)
if positive > 0 {
mant.Mul(&mant, scale)
} else {
mant.Quo(&mant, scale)
}
ten := newF().SetInt64(10)
i64exp := iexp.Int64()
// For numbers not too far from one, print without the E notation.
// Shouldn't happen (exp must be large to get here) but just
// in case, we keep this around.
if -4 <= i64exp && i64exp <= 11 {
if i64exp > 0 {
for i := 0; i < int(i64exp); i++ {
mant.Mul(&mant, ten)
}
} else {
for i := 0; i < int(-i64exp); i++ {
mant.Quo(&mant, ten)
}
}
fmt.Sprintf("%g\n", &mant)
} else {
sign := ""
if mant.Sign() < 0 {
sign = "-"
mant.Neg(&mant)
}
// If it has a leading zero, rescale.
digits := mant.Text('g', 12)
for digits[0] == '0' {
mant.Mul(&mant, ten)
if positive > 0 {
i64exp--
} else {
i64exp++
}
digits = mant.Text('g', 12)
}
return fmt.Sprintf("%s%se%c%d\n", sign, digits, "-+"[positive], i64exp)
}
}
if format != "" {
verb, prec, ok := conf.FloatFormat()
if ok {
Expand Down
7 changes: 7 additions & 0 deletions value/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var (
floatE *big.Float
floatPi *big.Float
floatLog2 *big.Float
floatLog10 *big.Float
floatOne *big.Float
floatTwo *big.Float
floatMinusOne *big.Float
Expand All @@ -39,6 +40,8 @@ const strPi = "3.141592653589793238462643383279502884197169399375105820974944592

const strLog2 = "0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875420014810205706857336855202357581305570326707516350759619307275708283714351903070386238916734711233501153644979552391204751726815749320651555247341395258829504530070953263666426541042391578149520437404303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952606683411372738737229289564935470257626520988596932019650585547647033067936544325476327449512504060694381471046899465062201677204245245296126879465461931651746813926725041038025462596568691441928716082938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866385231381816767514386674766478908814371419854942315199735488037516586127535291661000710535582498794147295092931138971559982056543928717000721808576102523688921324497138932037843935308877482597017155910708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347648114941864238677677440606956265737960086707625719918473402265146283790488306203306114463007371948900274364396500258093651944304119115060809487930678651588709006052034684297361938412896525565396860221941229242075743217574890977067526871158170511370091589426654785959648906530584602586683829400228330053820740056770530467870018416240441883323279838634900156312188956065055315127219939833203075140842609147900126516824344389357247278820548627155274187724300248979454019618723398086083166481149093066751933931289043164137068139777649817697486890388778999129650361927071088926410523092478391737350122984242049956893599220660220465494151061391878857442455775102068370308666194808964121868077902081815885800016881159730561866761991873952007667192145922367206025395954365416553112951759899400560003665135675690512459268257439464831683326249018038242408242314523061409638057007025513877026817851630690255137032340538021450190153740295099422629957796474271381573638017298739407042421799722669629799393127069357472404933865308797587216996451294464918837711567016785988049818388967841349383140140731664727653276359192335112333893387095132090592721854713289754707978913844454666761927028855334234298993218037691549733402675467588732367783429161918104301160916952655478597328917635455567428638774639871019124317542558883012067792102803412068797591430812833072303008834947057924965910058600123415617574132724659430684354652111350215443415399553818565227502214245664400062761833032064727257219751529082785684213207959886389672771195522188190466039570097747065126195052789322960889314056254334425523920620303439417773579455921259019925591148440242390125542590031295370519220615064345837878730020354144217857580132364516607099143831450049858966885772221486528821694181270488607589722032166631283783291567630749872985746389282693735098407780493950049339987626475507031622161390348452994249172483734061366226383493681116841670569252147513839306384553718626877973288955588716344297562447553923663694888778238901749810273565524050"

const strLog10 = "2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058498078280597511938544450099781311469159346662410718466923101075984383191912922307925037472986509290098803919417026544168163357275557031515961135648465461908970428197633658369837163289821744073660091621778505417792763677311450417821376601110107310423978325218948988175979217986663943195239368559164471182467532456309125287783309636042629821530408745609277607266413547875766162629265682987049579549139549180492090694385807900327630179415031178668620924085379498612649334793548717374516758095370882810674524401058924449764796860751202757241818749893959716431055188481952883307466993178146349300003212003277656541304726218839705967944579434683432183953044148448037013057536742621536755798147704580314136377932362915601281853364984669422614652064599420729171193706024449293580370077189810973625332245483669885055282859661928050984471751985036666808749704969822732202448233430971691111368135884186965493237149969419796878030088504089796185987565798948364452120436982164152929878117429733325886079159125109671875109292484750239305726654462762009230687915181358034777012955936462984123664970233551745861955647724618577173693684046765770478743197805738532718109338834963388130699455693993461010907456160333122479493604553618491233330637047517248712763791409243983318101647378233796922656376820717069358463945316169494117018419381194054164494661112747128197058177832938417422314099300229115023621921867233372683856882735333719251034129307056325444266114297653883018223840910261985828884335874559604530045483707890525784731662837019533922310475275649981192287427897137157132283196410034221242100821806795252766898581809561192083917607210809199234615169525990994737827806481280587927319938934534153201859697110214075422827962982370689417647406422257572124553925261793736524344405605953365915391603125244801493132345724538795243890368392364505078817313597112381453237015084134911223243909276817247496079557991513639828810582857405380006533716555530141963322419180876210182049194926514838926922937079"

func newF() *big.Float {
return new(big.Float).SetPrec(conf.FloatPrec())
}
Expand All @@ -63,5 +66,9 @@ func Consts() (e, pi BigFloat) {
if !ok {
panic("setting log(2)")
}
floatLog10, ok = newF().SetString(strLog10)
if !ok {
panic("setting log(10)")
}
return BigFloat{newF().Set(floatE)}, BigFloat{newF().Set(floatPi)}
}

0 comments on commit 522bdae

Please sign in to comment.