Question

Tom Wu's excellent big integer library JSBN is missing the longValue function, so I have to write such myself. Below is my code, but it cannot produce right results.

var Cast_Int64 = function (v)
{
  var bytes = v.toByteArray();
  var value =
  (
    (new BigInteger(bytes[0]).and(new BigInteger(255))).shiftLeft(new BigInteger(56))
  )
    .or(
      (new BigInteger(bytes[1]).and(new BigInteger(255))).shiftLeft(new BigInteger(48))
  )
    .or(
      (new BigInteger(bytes[2]).and(new BigInteger(255))).shiftLeft(new BigInteger(40))
  )
    .or(
      (new BigInteger(bytes[3]).and(new BigInteger(255))).shiftLeft(new BigInteger(32))
  )
    .or(
      (new BigInteger(bytes[4]).and(new BigInteger(255))).shiftLeft(new BigInteger(24))
  )
    .or(
      (new BigInteger(bytes[5]).and(new BigInteger(255))).shiftLeft(new BigInteger(16))
  )
    .or(
      (new BigInteger(bytes[6]).and(new BigInteger(255))).shiftLeft(new BigInteger(8))
  )
    .or(new BigInteger(bytes[7]).and(new BigInteger(255)));
  return value;
};

I have an array of integer strings, which I try to cast to Int64, but it doesn't provide right answers.

The array of integer strings is:

var arr = [
"90655",
"123423",
"1",
"9223372032559808512",
"18446744071562067967",
"4294967295",
"18446744071562067968",
"0",
"346457745533644",
"18446744073623153357"
];

The right answers (in C# test base using (Int64)) are:

90655
123423
1
9223372032559808512
-2147483649
4294967295
-2147483648
0
346457745533644
-86398259

And my incorrect answers are:

99676226616033280
135705023634997248
72057594037927936
9223372032559808512
72057594029539327
72057594021150720
72057594029539328
0
88693182856612864
72057594037590442

I have jsbin, where you can test the function.

EDIT: If I replace Cast_Int64 with this:

var Cast_Int64 = function (v)
{
  return v;
}

then all goes well, but all numbers that should be negative (in C# test base), will be wrong:

90655
123423
1
9223372032559808512
18446744071562067967
4294967295
18446744071562067968
0
346457745533644
18446744073623153357

Code that works (adapted from the accepted answer):

var Cast_Int64 = function (v)
{
  if (v.compareTo(new BigInteger(2).pow(new BigInteger(63))) > 0)
  v = v.subtract(new BigInteger(2).pow(new BigInteger(64)));
  return v;
}

Or shorter (and a bit faster):

var Cast_Int64 = function (v)
{
  if (v.compareTo(new BigInteger("9223372036854775808",10)) > 0)
  v = v.subtract(new BigInteger("18446744073709551616",10));
  return v;
}

I put the replaced code in jsbin. BTW, there are already Cast_UInt64, Cast_Int32 and Cast_UInt32 functions.

Was it helpful?

Solution

The integer arithmetic could be thought as modular arithmetic (with modulo 2^p where p is number of bits). So negative value can be represented as value that exceeds 2^(p-1), namely -x = 2^p - x. For example, consider x=1: -1 = 2^p - 1. You can add 1 to both sides, then take modulo 2^p and you'll get 0 on both sides.

So in order to get correct result, just subtract 2^64 (in your case p=64) from every values that is greater than 2^63:

18446744073623153357 - 2^64 = -86398259
18446744071562067968 - 2^64 = -2147483648

BTW: from this you can infer connection between signed and unsigned integers.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top