英文:
Go/Golang: how to extract least significant digits from big.Float?
问题
在Go/Golang中,我有一个big.Float类型的变量,精度为3,324,000,用于表示一个包含1,000,000位数字的小数。这是计算π的迭代结果。
现在我想打印出最低有效的100位数字,即第999,900位到第1,000,000位。
我尝试使用fmt.Sprintf()和big.Text()将变量转换为字符串。然而,这两个函数都消耗了大量的处理时间,当进一步提高精度时,这变得不可接受(需要数小时甚至数天)。
我正在寻找一些函数,可以提取变量的最后100位(十进制)数字。
提前感谢您的支持。
英文:
In Go/Golang I have a variable of type big.Float with an (arbitrary) precision of 3,324,000 to represent a decimal number of 1,000,000 digits. It's the result of an iteration to calculate pi.
Now I want to print out the least significant 100 digits, i.e. digits 999,900 to 1,000,000.
I tried to convert the variable to a string by using fmt.Sprintf() and big.Text(). However, both functions consume a lot of processing time which gets unacceptable (many hours and even days) when further raising the precision.
I'm searching for some functions which extract the last 100 (decimal) digits of the variable.
Thanks in advance for your kind support.
答案1
得分: 2
标准库没有提供一个高效返回这些数字的函数,但是你可以计算它们。
更高效的方法是将你感兴趣的数字隔离出来并打印它们。这样可以避免对一个极大的数进行过多的计算,以确定每个单独的数字。
下面的代码展示了一种实现方式。你需要确保有足够的精度来准确生成它们。
package main
import (
"fmt"
"math"
"math/big"
)
func main() {
// 用更大的计算结果替换这里。
pi := big.NewFloat(math.Pi)
const (
// Pi: 3.1415926535897932...
// 输出: 5926535897
digitOffset = 3
digitLength = 10
)
// 将所需的数字移到小数点的右侧。
mult := pow(10, digitOffset)
digits := new(big.Float).Mul(pi, mult)
// 移除整数部分。
digits.Sub(digits, trunc(digits))
// 将数字移到小数点的左侧,并截断为表示所需数字的整数。
// 这样可以避免在小数点后简单地打印N个数字时出现不希望的四舍五入。
mult = pow(10, digitLength)
digits.Mul(digits, mult)
digits = trunc(digits)
// 显示接下来的 'digitLength' 个数字。用零填充。
fmt.Printf("%0*.0f\n", digitLength, digits)
}
// trunc 返回整数部分。
func trunc(n *big.Float) *big.Float {
intPart, accuracy := n.Int(nil)
_ = accuracy
return new(big.Float).SetInt(intPart)
}
// pow 计算 n^idx。
func pow(n, idx int64) *big.Float {
if idx < 0 {
panic("invalid negative exponent")
}
result := new(big.Int).Exp(big.NewInt(n), big.NewInt(idx), nil)
return new(big.Float).SetInt(result)
}
英文:
The standard library doesn't provide a function to return those digits efficiently, but you can calculate them.
It is more efficient to isolate the digits you are interested in and print them. This avoids excessive calculations of an extremely large number to determine each individual digit.
The code below shows a way it can be done. You will need to ensure you have enough precision to generate them accurately.
package main
import (
"fmt"
"math"
"math/big"
)
func main() {
// Replace with larger calculation.
pi := big.NewFloat(math.Pi)
const (
// Pi: 3.1415926535897932...
// Output: 5926535897
digitOffset = 3
digitLength = 10
)
// Move the desired digits to the right side of the decimal point.
mult := pow(10, digitOffset)
digits := new(big.Float).Mul(pi, mult)
// Remove the integer component.
digits.Sub(digits, trunc(digits))
// Move the digits to the left of the decimal point, and truncate
// to an integer representing the desired digits.
// This avoids undesirable rounding if you simply print the N
// digits after the decimal point.
mult = pow(10, digitLength)
digits.Mul(digits, mult)
digits = trunc(digits)
// Display the next 'digitLength' digits. Zero padded.
fmt.Printf("%0*.0f\n", digitLength, digits)
}
// trunc returns the integer component.
func trunc(n *big.Float) *big.Float {
intPart, accuracy := n.Int(nil)
_ = accuracy
return new(big.Float).SetInt(intPart)
}
// pow calculates n^idx.
func pow(n, idx int64) *big.Float {
if idx < 0 {
panic("invalid negative exponent")
}
result := new(big.Int).Exp(big.NewInt(n), big.NewInt(idx), nil)
return new(big.Float).SetInt(result)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论