4

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.

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

How should I modify my Cast_Int64 function?
Algorithm roughly described in second paragraph. What part do you don't understand? I can't tell you what code to write because I haven't look to the library you mentioned.
I got it. I'll add the replacement to the question. Thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.