peterolson / BigInteger.js

An arbitrary length integer library for Javascript
The Unlicense
1.12k stars 187 forks source link

Two's complement representation #191

Closed r3econ closed 1 year ago

r3econ commented 5 years ago

Many times in the docs I see that the arguments passed to functions should be represented using two's complement representation. My question is how to convert a number to its two's complement representation.

What I tried is to go with:

number.not().add(1)

However this does not bring correct results. The numbers I'm working with are very large negative integers. I want to convert a large integer to to its hex signed 2's complement.

peterolson commented 5 years ago

Can you give an example of the operation that you want to do and the output that you expect?

srghma commented 2 years ago

how about

let invert = str => str.split('').map(x => x === "0" ? "1" : "0").join('')
let myOnesComplement = bn => new BigNumber(invert(bn.toString(2)), 2)
let myTwosComplement = bn => myOnesComplement(bn).addn(1)

print(myOnesComplement(new BigNumber("-4", 10)))
// "decimal = 3, binary = 11"
print(myTwosComplement(new BigNumber("-4", 10)))
// "decimal = 4, binary = 100"
Yaffle commented 2 years ago

@srghma but you forgot to invert infinite number of leading zeros

srghma commented 2 years ago

@Yaffle could You post fixed variant, please

Yaffle commented 2 years ago

@srghma it should look like BigInt.asUintN perhaps

Rudxain commented 2 years ago

@Yaffle But how to invert infinite leading 0s? I thought this works by using a finite numeral with a floating (movable) sign bit, so only the sign bit must be inverted and included with the numeral (regardless if it's 0 or 1), am I missing something?

Edit: Wait I realized my mistake. "1110" <-> "0001", and "010" <-> "101", so the function treats all bits the same way, without conditionally discarding leading bits

Rudxain commented 2 years ago

@srghma

let invert = str => str.split('').map(x => x === "0" ? "1" : "0").join('')

Can be converted to:

let inv = s => s.replace(/./gs, c => c == "0" ? "1" : "0")

But it's less readable, I guess