将字节片中的负数转换为 int
Convert negative digit in byte slice to int
我需要帮助
Debezium(https://debezium.io/) 将十进制数字转换为 base64 字符串中的整数,精度作为 json 中的参数 在 java 中,它像这个例子一样解码
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-
它returns9777216
因为当我在 "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
expects the number in 2's complement binary representation, while Go's big.Int.SetBytes()
的构造函数需要一个无符号整数值(按大端字节顺序):
SetBytes interprets buf as the bytes of a big-endian unsigned integer, sets z to that value, and returns z.
我们可以做的是使用Int.SetBytes()
继续,但是如果数字是负数,我们必须将其转换为二进制数据以2的补码表示的数字。如果它的第一位是1(这是第一个字节的最高位),我们就可以判断它是否为负数。
这个转换很简单:如果输入使用 n
字节表示,则使用 n+1
字节构造一个数字,其中第一个是 1
,其余是 0
(使用 n
字节加 1 的最大可表示数)。减去 (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()
.
可以通过将结果除以 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>
我需要帮助
Debezium(https://debezium.io/) 将十进制数字转换为 base64 字符串中的整数,精度作为 json 中的参数 在 java 中,它像这个例子一样解码
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-
它returns9777216
因为当我在 "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
expects the number in 2's complement binary representation, while Go's big.Int.SetBytes()
的构造函数需要一个无符号整数值(按大端字节顺序):
SetBytes interprets buf as the bytes of a big-endian unsigned integer, sets z to that value, and returns z.
我们可以做的是使用Int.SetBytes()
继续,但是如果数字是负数,我们必须将其转换为二进制数据以2的补码表示的数字。如果它的第一位是1(这是第一个字节的最高位),我们就可以判断它是否为负数。
这个转换很简单:如果输入使用 n
字节表示,则使用 n+1
字节构造一个数字,其中第一个是 1
,其余是 0
(使用 n
字节加 1 的最大可表示数)。减去 (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()
.
可以通过将结果除以 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>