英文:
Splitting big.Int by digit
问题
我正在尝试将big.Int
拆分为多个int64
,使得每个部分都是较大数字的一部分,标准偏移量为18位数字。例如,给定以下输入值1234512351234088800000999
,我期望得到以下输出:[351234088800000999, 1234512]
。对于负数,我期望所有部分都为负数(即-1234512351234088800000999
会产生[-351234088800000999, -1234512]
)。
我已经知道可以使用以下代码来获得想要的结果:
func Split(input *big.Int) []int64 {
const width = 18
asStr := in.Coefficient().Text(10)
strLen := len(asStr)
offset := 0
if in.IsNegative() {
offset = 1
}
length := int(math.Ceil(float64(strLen-offset) / width))
ints := make([]int64, length)
for i := 1; i <= length; i++ {
start := strLen - (i * width)
end := start + width
if start < 0 || (start == 1 && asStr[0] == '-') {
start = 0
}
ints[i-1], _ = strconv.ParseInt(asStr[start:end], 10, 64)
if offset == 1 && ints[i-1] > 0 {
ints[i-1] = 0 - ints[i-1]
}
}
return ints
}
然而,我不喜欢使用字符串解析,也不喜欢使用strconv
。有没有一种方法可以直接利用big.Int
来实现这个功能?
英文:
I'm trying to split a big.Int
into a number of int64
s such that each is a portion of the larger number, with a standard offset of 18 digits. For example, given the following input value of 1234512351234088800000999
, I would expect the following output: [351234088800000999, 1234512]
. For negative numbers, I would expect all of the parts to be negative (i.e. -1234512351234088800000999
produces [-351234088800000999, -1234512]
).
I already know I can do this to get the result I want:
func Split(input *big.Int) []int64 {
const width = 18
asStr := in.Coefficient().Text(10)
strLen := len(asStr)
offset := 0
if in.IsNegative() {
offset = 1
}
length := int(math.Ceil(float64(strLen-offset) / width))
ints := make([]int64, length)
for i := 1; i <= length; i++ {
start := strLen - (i * width)
end := start + width
if start < 0 || (start == 1 && asStr[0] == '-') {
start = 0
}
ints[i-1], _ = strconv.ParseInt(asStr[start:end], 10, 64)
if offset == 1 && ints[i-1] > 0 {
ints[i-1] = 0 - ints[i-1]
}
}
return ints
}
However, I don't like the idea of using string-parsing nor do I like the use of strconv
. Is there a way I can do this utilizing the big.Int
directly?
答案1
得分: 1
你可以使用DivMod
函数来完成你在这里需要的操作,需要特别注意处理负数:
var offset = big.NewInt(1e18)
func Split(input *big.Int) []int64 {
rest := new(big.Int)
rest.Abs(input)
var ints []int64
r := new(big.Int)
for {
rest.DivMod(rest, offset, r)
ints = append(ints, r.Int64() * int64(input.Sign()))
if rest.BitLen() == 0 {
break
}
}
return ints
}
通过将每个输出乘以input.Sign()
,可以确保如果输入为负数,则每个输出都为负数。输出值乘以1e18乘以它们在输出中的位置的总和应该等于输入值。
英文:
You can use the DivMod
function to do what you need here, with some special care to handle negative numbers:
var offset = big.NewInt(1e18)
func Split(input *big.Int) []int64 {
rest := new(big.Int)
rest.Abs(input)
var ints []int64
r := new(big.Int)
for {
rest.DivMod(rest, offset, r)
ints = append(ints, r.Int64() * int64(input.Sign()))
if rest.BitLen() == 0 {
break
}
}
return ints
}
Multiplying each output by input.Sign()
ensures that each output will be negative if the input is negative. The sum of the output values multiplied by 1e18 times their position in the output should equal the input.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论