繁体   English   中英

将字节片中的负数转换为int

[英]Convert negative digit in byte slice to int

我需要帮助

Debezium( https://debezium.io/ )将base64字符串中的十进制数字转换为整数,并以json中的参数作为精度。

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Base64;

public class HelloWorld{

     public static void main(String []args){
        String encoded = "lTBA";
        int scale = 4;
        final BigDecimal decoded = new BigDecimal(new BigInteger(Base64.getDecoder().decode(encoded)), scale);
        System.out.println(decoded);        
     }
}

"lTBA" = -700

但是在Golang中,类似的例子有些麻烦

包主

import (
    "encoding/base64"
    "fmt"
    "math/big"
)

func main() {
    data, _ := base64.StdEncoding.DecodeString("lTBA")

    bigInt := new(big.Int).SetBytes(data).String()
    fmt.Println(bigInt)
}

https://play.golang.org/p/3Xdq9x6B9V-返回9777216

因为当我在“ math / big / Int”中使用SetBytes时,它总是将数字设置为正数

// SetBytes interprets buf as the bytes of a big-endian unsigned
// integer, sets z to that value, and returns z.
func (z *Int) SetBytes(buf []byte) *Int {
    z.abs = z.abs.setBytes(buf)
    z.neg = false
    return z
}

Java的BigInteger构造方法期望数字以2的补码二进制表示形式,而Go的big.Int.SetBytes()期望无符号整数值(按大端字节顺序):

SetBytes将buf解释为大端无符号整数的字节,将z设置为该值,然后返回z。

我们可以使用Int.SetBytes()进行操作,但是如果数字为负数,我们必须将其转换为2的补码表示的二进制数据的数字。 我们可以判断它的第一位是否为1(这是第一个字节的最高位)是否为负。

这种转换很简单:如果输入使用n个字节表示,则使用n+1个字节构造一个数字,其中第一个为1 ,其余为0 (使用n个字节加1的最大可表示数字)。 从该数字减去( Int.Sub() )的输入将得出2的补数形式的数字的绝对值,因此我们只需要在此数字上Int.Neg()一个负号: Int.Neg()

可以通过将结果( Int.Div() )除以10的数字来应用scale 我们可以通过将零scale附加到1来构造这样的数字。

这是一个完成所有这些操作的decode()函数。 它并未针对性能进行优化,但可以完成以下工作:

func decode(in string, scale int) (out *big.Int, err error) {
    data, err := base64.StdEncoding.DecodeString(in)
    if err != nil {
        return
    }

    out = new(big.Int).SetBytes(data)

    // Check if negative:
    if len(data) > 0 && data[0]&0x80 != 0 {
        // It's negative.
        // Convert 2's complement negative to abs big-endian:
        data2 := make([]byte, len(data)+1)
        data2[0] = 1
        temp := new(big.Int).SetBytes(data2)
        out.Sub(temp, out)

        // Apply negative sign:
        out.Neg(out)
    }

    // Apply scale:
    if scale > 0 {
        temp, _ := new(big.Int).SetString("1"+strings.Repeat("0", scale), 10)
        out.Div(out, temp)
    }

    return
}

测试示例:

n, err := decode("lTBA", 4)
fmt.Println(n, err)

输出(在Go Playground上尝试):

-700 <nil>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM