将big.Int按数字拆分

huangapple go评论77阅读模式
英文:

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 int64s 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 &lt;= length; i++ {
		start := strLen - (i * width)
		end := start + width
		if start &lt; 0 || (start == 1 &amp;&amp; asStr[0] == &#39;-&#39;) {
			start = 0
		}

		ints[i-1], _ = strconv.ParseInt(asStr[start:end], 10, 64)
		if offset == 1 &amp;&amp; ints[i-1] &gt; 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.

huangapple
  • 本文由 发表于 2022年11月14日 15:13:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/74428040.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定