Just as an exercise for a project I am working on, I need to be able to parse arbitrary precision numbers and be able to print them back out and get the exact same output string as the input string.
I can not figure out the incantation to do this with big.Float
!
I tried using f, i, err := big.ParseFloat(pi, 10, big.MaxPrec, big.AwayFromZero)
and I got the exact some wrong output, so I can not tell if the parsing is wrong, the formatting the output is wrong or BOTH?
These functions are not very well documented, as in the i
return value is not described what it is supposed to represent anywhere I can find. It has a value of 10
every time, I can only assume it is the base.
package main
import (
"fmt"
"math/big"
"strings"
)
func main() {
pi := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644"
fmt.Println(pi)
precision := uint(len(pi[strings.Index(pi,".")+1:]))
fmt.Printf("%d decimal digits!\n", precision)
bf := big.NewFloat(0.0)
bf, _ = bf.SetPrec(precision).SetMode(bf.Mode()).SetString(pi)
fmt.Println(bf.Text('f',int(precision)))
}
this is the output I am getting
3.141592653589793238462643383279502884197169399375105820974944592307816406286208
99862803482534211706798214808651328230664709384460955058223172535940812848111745
02841027019385211055596446229489549303819644288109756659334461284756482337867831
65271201909145648566923460348610454326648213393607260249141273724587006606315588
1748815209209628292540917153644
349 decimal digits!
3.141592653589793238462643383279502884197169399375105820974944592307816406286208
99862803482534211706798214642892769097375992970630463040280967955002394205104670
93398509790876622872910336294129674153835313200604005620450374388405009045870250
42707837345817603660943583398075476645872182159499972077156507317945849377949230
0745914690196514129638671875000
mje
(Jeff Emanuel)
February 22, 2022, 4:23pm
2
mantissa precision of x in bits.
Digits in base-10 take more than 1 bit. You are basing precision on the number of digits. At least triple it.
precision x 3 is no where near enough, precision x 7 gets the correct answer sort of.
as you can see, I get the original string PLUS a bunch of rounding garbage at the end.
how would I calculate the correct * bits precision based on the number of desired digits in the output string?
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002244342506374987052728132873357764604822964011725723498156139035608263529693321324611087760931638291534783804429504024063970113225287605729963719722383580878304141959206687069400914796848561621434478110671369148893967123772756235371122602256507537069295793796127829048985435018724653366850521683797027866210566225126917930722700540281778806181488530238605442879753445529001873898888929241864013642282373527291515685288403981807650734267848295316694745558591914884141327648624551152976025240472366982876042065424920222257500605683086490572532495407799867513435663181757387051418102492504661099733895817691933392065321975406088794616695914589059426846076572409593363011614759573979870328010001015131814985977529961056716665782401251298757553305676392622078175716128094105318036037245992472681494427947436144326364838683179041263870046413457172155738170850090737732421416031506418182930764950812479381058736513575328259855587826691707281198805818862277495355406830418592809361721477237559115847998907779919675848738643420198693152512349267893520195348481384845351896090256789774024980305634166361874489554298999467170401080881950315354127157986245696801549849750033397305982685708142528398925768672801947396154320512030099540703574095339226368627750879580770901088754012337545509255182543249838242985702416360011638303226834983986987743539557515819170488243938973917949619935857136645165558615729339233345028341636697904845161310408856339696647756621712434792748303616469785554055231767976392050919715124254881461507226059126555805330182014130173637310850569765132473800857139233811910170967773594655986084933999505845270291677052663693276509280026011803914534022466858304012404801142110954970121383666992187500
after some checking it seems that precision == 2400 is the smallest number that I can use that gets me the correct output + the zeros and garbage at the end.
mje
(Jeff Emanuel)
February 22, 2022, 7:21pm
4
It looks like an exact match when multiplying by 4. Go Playground - The Go Programming Language
NobbZ
(Norbert Melzer)
February 22, 2022, 7:25pm
5
A single decimal digit can take values from 0 to 9, so 10 different values.
So you need log2(10) bit to represent a single decimal digit.
mje
(Jeff Emanuel)
February 22, 2022, 7:35pm
6
Thanks, I was being lazy. With log2(10) you save 236 bits, FWIW
I was doing this;
precision := uint(len(pi[strings.Index(pi, ".")+1:]) * 4)
and that does not work, neither does
precision := uint(len(pi[strings.Index(pi, ".")+1:])) * 4
but this works, this is mine numbing stupid behavior
bf, _ = bf.SetPrec(precision * 4).SetMode(bf.Mode()).SetString(pi)
this is the smallest precision bit number that gives the correct result.
bf, _ = bf.SetPrec(1161).SetMode(bf.Mode()).SetString(pi)
1160 rounds the last digit up, 1159 rounds the last digit down, 1161 is just right.
Thanks for all the replies!
NobbZ
(Norbert Melzer)
February 22, 2022, 8:09pm
8
Those extra bits are for the leading 3
in front of the comma!
so given an arbitrary number of digits before the .
and after the .
how would one calculate the correct number of bits to feed into the .SetPrec()
function?
NobbZ
(Norbert Melzer)
March 13, 2022, 7:12am
10
Consider all digits, not only those after the comma.
So here is a complete working solution/example that takes into consideration the integer and fractional digit counts and as far as my limited testing shows, returns the exact same string representation as the input value.
pi := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644"
fmt.Printf("%s\n", pi)
integerDigitCount := strings.Index(pi, ".")
fractionalDigitCount := len(pi) - (integerDigitCount + 1) // exclude the decimal from the count
fmt.Printf("integer digit count: %d\n", integerDigitCount)
fmt.Printf("factional digit count: %d\n", fractionalDigitCount)
bf := big.NewFloat(0.0)
precision := uint(math.Ceil(float64(fractionalDigitCount) * math.Log2(10.0)) + float64(integerDigitCount) * math.Log2(10.0))
fmt.Printf("calculated precision %d\n", precision)
bf, _ = bf.SetPrec(uint(precision)).SetString(pi)
ppi := bf.Text('f', fractionalDigitCount)
fmt.Printf("%s\n", ppi)
also according to the documentation and my testing, a negative value for precision
in the bf.Text()
method will generate the minumim amount of digits to represent the fractional part.
ppi := bf.Text('f', -1)
Will always generate the exact same output as the input without you having to store the number of fractional digits to use later.
system
(system)
Closed
July 22, 2022, 6:27pm
12
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.