簡體   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