Конструктор 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.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>