Power and Root functions using big.Float in Golang

in #tutorial3 years ago (edited)

Welcome to my first post as @gopher23. This account will be used for publishing useful things for anyone learning to program in Google's language Go

Of course the content will always be 100% my own, original (usually derived), relating to work I am doing.

How to compute a stupidly precise nth root in Golang

I am in the process of writing some code to generate an exponential decay sequence for an altcoin I am developing, which requires absurdly humongous numbers and especially floating point precision.

Well, really it's exponential growth, but when tokens are issued, they add together to become the total supply, which is the iterative version of exponential growth.

I want to make the supply grow by a precise annual percentage, so the block rewards must decay also by a precise percentage, and by using stupidly accurate big numbers it hits very close to the precise supply rate target I am aiming for, which will be 3.125% per year, in this case (because I like powers of two and their inverses, 1/32).

Enough rambling, here is the code, and afterwards a few comments.


import "math/big"

func Pow(a *big.Float, e uint64) *big.Float {
    result := Zero().Copy(a)
    for i:=uint64(0); i<e-1; i++ {
        result = Mul(result, a)
    }
    return result
}

func Root(a *big.Float, n uint64) *big.Float {
    limit := Pow(New(2), 256)
    n1 := n-1
    n1f, rn := New(float64(n1)), Div(New(1.0), New(float64(n)))
    x, x0 := New(1.0), Zero()
    _ = x0
    for {
        potx, t2 := Div(New(1.0), x), a
        for b:=n1; b>0; b>>=1 {
            if b&1 == 1 {
                t2 = Mul(t2, potx)
            }
            potx = Mul(potx, potx)
        }
        x0, x = x, Mul(rn, Add(Mul(n1f, x), t2) )
        if Lesser(Mul(Abs(Sub(x, x0)), limit), x) { break } 
    }
    return x
}

func Abs(a *big.Float) *big.Float {
    return Zero().Abs(a)
}

func New(f float64) *big.Float {
    r := big.NewFloat(f)
    r.SetPrec(256)
    return r
}

func Div(a, b *big.Float) *big.Float {
    return Zero().Quo(a, b)
}

func Zero() *big.Float {
    r := big.NewFloat(0.0)
    r.SetPrec(256)
    return r
}

func Mul(a, b *big.Float) *big.Float {
    return Zero().Mul(a, b)
}

func Add(a, b *big.Float) *big.Float {
    return Zero().Add(a, b)
}

func Sub(a, b *big.Float) *big.Float {
    return Zero().Sub(a, b)
}

func Lesser(x, y *big.Float) bool {
    return x.Cmp(y) == -1
}


First thing, the math/big library is strangely written, as though maybe it was written by a committee that couldn't decide whether the variables would be changed via their receivers, or if results would be passed back in return values.

Well, it's not really a problem, but for the sake of readability and reducing the cognitive load of using prefix operators, since there is no overloading in Go (not a bad thing, really!) you can see I implemented short wrapper functions for all the things the Pow() and Root() function at the top require.

Note that both of the functions only accept integer index/radix values. This is because it is an exercise for the reader to implement decimal roots. If you know a reasonable bit of basic algebra, you will know that rational (and therefore also decimal) powers are also able to be expressed as the multiplication of the the power of the numerator exponent by the root of the denominator exponent. The power of 0.5 can be calculated as the base multiplied by the square (2) root of the same base.

Follow me to learn more useful things for budding Gophers especially relating to cryptocurrency programming!

Sort:  

nice article :) love to see more from you

my friend is searching for somebody who knows golang, msg me for info

@gopher23, congratulations on making your first post! I gave you an upvote!

Please give me a follow and take a moment to read this post regarding commenting and spam.
(tl;dr - if you spam, you will be flagged!)

Congratulations @gopher23! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

You published your First Post
You got a First Vote

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!