duan7007 2018-12-18 08:37
浏览 452
已采纳

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

I need help

Debezium(https://debezium.io/) convert decimal digits as integer in base64 string with precision as parameter in json In java it decoded like this example

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

but in Golang I have some troubles in similar example

package main

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- It returns 9777216

Because when I use SetBytes in "math/big/Int" it set digit as positive always

// 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
}
  • 写回答

1条回答 默认 最新

  • du8791069 2018-12-18 10:22
    关注

    Constructor of Java's BigInteger expects the number in 2's complement binary representation, while Go's big.Int.SetBytes() expects an unsigned integer value (in big-endian byte order):

    SetBytes interprets buf as the bytes of a big-endian unsigned integer, sets z to that value, and returns z.

    What we can do is proceed using Int.SetBytes(), but if the number is negative, we have to transform it to the number the binary data represented in 2's complement. We can tell if it's negative if its first bit is 1 (which is the highest bit of the first byte).

    This transformation is simple: if the input is represented using n bytes, construct a number using n+1 bytes where the first is 1, the rest is 0 (the max representable number using n bytes plus 1). Subtracting (Int.Sub()) the input from this number will give you the absolute value of the number in 2's complement, so we just have to apply a negative sign on this number: Int.Neg().

    Scale can be applied by dividing (Int.Div()) the result by a number being 10scale. We may construct such a number by appending scale zeros to a 1.

    Here is a decode() function that does all this. It's not optimized for performance, but it does the job:

    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
    }
    

    Example testing it:

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

    Output (try it on the Go Playground):

    -700 <nil>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分