Golang中如何解析big.Float并确保输出与输入完全一致
Golang中如何解析big.Float并确保输出与输入完全一致 作为我正在进行的项目的一个练习,我需要能够解析任意精度的数字,并能够将它们打印出来,得到与输入字符串完全相同的输出字符串。
我无法找到使用 big.Float 实现这一点的正确方法!
我尝试使用 f, i, err := big.ParseFloat(pi, 10, big.MaxPrec, big.AwayFromZero),但我得到了完全相同的错误输出,所以我无法判断是解析过程出错了,还是格式化输出出错了,或者两者都有问题?
这些函数的文档记录得不是很好,例如 i 返回值在任何我能找到的地方都没有描述它应该代表什么。每次它的值都是 10,我只能假设它是基数。
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)))
}
这是我得到的输出
3.141592653589793238462643383279502884197169399375105820974944592307816406286208
99862803482534211706798214808651328230664709384460955058223172535940812848111745
02841027019385211055596446229489549303819644288109756659334461284756482337867831
65271201909145648566923460348610454326648213393607260249141273724587006606315588
1748815209209628292540917153644
349 decimal digits!
3.141592653589793238462643383279502884197169399375105820974944592307816406286208
99862803482534211706798214642892769097375992970630463040280967955002394205104670
93398509790876622872910336294129674153835313200604005620450374388405009045870250
42707837345817603660943583398075476645872182159499972077156507317945849377949230
0745914690196514129638671875000
更多关于Golang中如何解析big.Float并确保输出与输入完全一致的实战教程也可以访问 https://www.itying.com/category-94-b0.html
请考虑所有数字,而不仅仅是小数点后的数字。
更多关于Golang中如何解析big.Float并确保输出与输入完全一致的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
x 的尾数精度(以位为单位)。
以10为基数的数字需要超过1位来表示。你是基于数字的位数来确定精度的。至少将其乘以三。
看起来乘以4时是一个精确匹配。Go Playground - The Go Programming Language
那么,给定小数点前和小数点后任意数量的数字,如何计算应传入 .SetPrec() 函数的正确位数呢?
一个十进制数字可以取0到9的值,所以有10个不同的值。
因此,你需要log2(10)位来表示一个十进制数字。
谢谢,我太懒了。使用 log2(10) 可以节省 236 位,仅供参考。
Go Playground - The Go Programming Language
Go 是一种开源编程语言,可以轻松构建简单、可靠且高效的软件。
我之前是这样做的:
precision := uint(len(pi[strings.Index(pi, ".")+1:]) * 4)
但这行不通,下面这个也不行:
precision := uint(len(pi[strings.Index(pi, ".")+1:])) * 4
然而这个却可以,这真是让人无语的愚蠢行为:
bf, _ = bf.SetPrec(precision * 4).SetMode(bf.Mode()).SetString(pi)
这是能给出正确结果的最小精度位数:
bf, _ = bf.SetPrec(1161).SetMode(bf.Mode()).SetString(pi)
1160 会将最后一位数字向上舍入,1159 会将最后一位数字向下舍入,1161 则刚刚好。
感谢所有的回复!
以下是一个完整的工作解决方案/示例,它考虑了整数和小数部分的位数。根据我有限的测试,它返回与输入值完全相同的字符串表示。
pi := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644"
fmt.Printf("%s\n", pi)
integerDigitCount := strings.Index(pi, ".")
fractionalDigitCount := len(pi) - (integerDigitCount + 1) // 从计数中排除小数点
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)
另外,根据文档和我的测试,bf.Text() 方法中 precision 参数为负值将生成表示小数部分所需的最少位数。
ppi := bf.Text('f', -1)
这将始终生成与输入完全相同的输出,而无需您存储小数位数以供后续使用。
要确保 big.Float 的解析和输出与输入字符串完全一致,关键在于正确设置精度和格式化参数。你的代码接近正确,但需要调整精度设置和解析方式。
问题在于 big.NewFloat(0.0) 的初始精度是53位(IEEE 754双精度),这不足以表示你的长数字。虽然你后来调用了 SetPrec(precision),但这里的 precision 是十进制位数,而 SetPrec 需要的是二进制位数。
以下是修正后的代码:
package main
import (
"fmt"
"math/big"
"strings"
)
func main() {
pi := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644"
// 解析big.Float
f := new(big.Float)
f.SetPrec(big.MaxPrec) // 使用最大精度
f.SetMode(big.ToNearestEven)
// 解析字符串
_, success := f.SetString(pi)
if !success {
fmt.Println("解析失败")
return
}
// 计算需要的十进制位数
decimalDigits := len(pi) - strings.Index(pi, ".") - 1
// 输出,确保与输入完全一致
fmt.Println("输入字符串:")
fmt.Println(pi)
fmt.Printf("\n输出结果(%d位小数):\n", decimalDigits)
fmt.Println(f.Text('f', decimalDigits))
// 验证是否一致
output := f.Text('f', decimalDigits)
if pi == output {
fmt.Println("\n✓ 输入输出完全一致")
} else {
fmt.Println("\n✗ 输入输出不一致")
}
}
或者使用 big.ParseFloat 的版本:
package main
import (
"fmt"
"math/big"
"strings"
)
func main() {
pi := "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644"
// 解析字符串
f, i, err := big.ParseFloat(pi, 10, big.MaxPrec, big.ToNearestEven)
if err != nil {
fmt.Println("解析错误:", err)
return
}
// i 是实际使用的基数(这里是10)
fmt.Printf("解析成功,基数: %d\n", i)
// 计算需要的十进制位数
decimalDigits := len(pi) - strings.Index(pi, ".") - 1
// 输出
fmt.Println("\n输入字符串:")
fmt.Println(pi)
fmt.Printf("\n输出结果:\n")
fmt.Println(f.Text('f', decimalDigits))
// 验证
output := f.Text('f', decimalDigits)
if pi == output {
fmt.Println("\n✓ 验证通过")
}
}
关键点:
- 使用
big.MaxPrec确保足够的二进制精度 big.ParseFloat的返回值i是实际使用的基数(对于十进制字符串就是10)Text('f', decimalDigits)中的decimalDigits必须足够大以包含所有小数位- 使用
big.ToNearestEven作为舍入模式(这是默认模式)
对于你的具体例子,输出应该是:
输入字符串:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644
输出结果:
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153644
✓ 输入输出完全一致



