Int32 computation difference between Java and JavaScript [duplicate] - javascript

This question already has answers here:
Why would I use Math.imul()?
(3 answers)
Is floating point math broken?
(31 answers)
Closed 10 days ago.
I need to rewrite some legacy Java code performing arithmetic transformations from Java to TypeScript/JavaScript. The problem is the legacy code uses the int Java type (signed 32-bits) and relies on overflows. I almost got what I want using Int32Array in JavaScript, but I still have a difference I can't explain. Look below.
Java:
int current = -1599751945;
int next = current * 0x08088405 + 1;
System.out.println("next = " + next);
Output: next = 374601940
Javascript:
const a = new Int32Array(4)
a[0] = -1599751945
a[1] = 0x08088405
a[2] = 1
a[3] = a[0]*a[1] + a[2]
console.log('a[3] = ' + a[3])
Output: a[3] = 374601952
Can someone explain the difference? And how can I get same result in JavaScript? I tried shift operations, coerce with |0, methods to convert etc., but best result is the one above.

Use Math.imul() in JavaScript. That should produce the correct result.
const a = new Int32Array(4)
a[0] = -1599751945
a[1] = 0x08088405
a[2] = 1
a[3] = Math.imul(a[0], a[1]) + a[2]
console.log('a[3] = ' + a[3])
Additional details as to why can be found here.

I can't provide a definitive answer as to exactly why you get these exact numbers; but consider that all numbers in JS are doubles.
So, whereas current * 0x08088405 is done using integer arithmetic in Java, a[0]*a[1] is done using double arithmetic in JS, so these intermediate results are different; and the limited precision of a double means that adding 1 to that doesn't actually change the value:
console.log(a[0]*a[1]) => -215607868985706270
console.log(a[0]*a[1] + a[2]) => = -215607868985706270
Compare this to Java, where integer arithmetic is used:
int[] a = { -1599751945, 0x08088405, 1};
System.out.println(a[0]*a[1]) => 374601939
System.out.println(a[0]*a[1] + a[2]) => 374601940
If we make Java do this in double arithmetic:
double[] a = { -1599751945, 0x08088405, 1};
System.out.println(a[0]*a[1]); => -2.15607868985706272E17
System.out.println(a[0]*a[1] + a[2]); => -2.15607868985706272E17
You can see that this is almost the same, but differs in the least significant digit:
-215607868985706270 // JS
-215607868985706272 // Java
I don't know why there is such a difference here.

Floating point numbers only support precision up to a specific number of digits. JavaScript promotes numbers larger than 32 bits to floating point numbers.
Java is "more correct" here.
// -215607868985706285 is the 64 bit result of your multiplication
console.log(-215607868985706285); // will print -215607868985706285
See Is floating point math broken? for a general discussion of this topic.

Related

Is parseInt doesn't needed for '*' in JavaScript? [duplicate]

This question already has answers here:
What exactly is Type Coercion in Javascript?
(9 answers)
Closed 2 years ago.
I have array, by which at some point am mapping the array and calculating sum and percentages. So while implementing the logic i saw that, when i use '*' directly its working but when i use '+' it just adds the two string
For example:
const a = '100';
const b = '10';
const c = a * b;
const d = a + b;
console.log(d)
When i checked the d , it gives '10010' and when c it gives '1000' ! How is this ?
But when i use parseInt(a) + parseInt(b) it works perfectly with 110 as output
In JavaScript there are no primitive datatypes like int, float etc. There are only variables which can be initialized with everything you need. For your example
const a = 100;
const b = 10;
const c = a * b;
const d = a + b;
console.log(d);
should work perfectly, because I removed ''. With '' the constant thinks it is a string provided. Without '' there are just the numbers saved in the constants. Also + doesn't work in your example, because as I said the constants think the numbers are a string due to ''. So it just puts this two "strings" together and not summing them up.

javascript division giving wrong answer? [duplicate]

This question already has answers here:
How to deal with floating point number precision in JavaScript?
(47 answers)
Closed 9 years ago.
alert(5.30/0.1);
This gives 52.99999999999999 but should be 53. Can anybody tell how and why?
I want to find that a number is divisible by a given number. Note that one of the number may be a float.
For the same reason that
0.1 * 0.2 //0.020000000000000004
Some decimal numbers can't be represented in IEEE 754, the mathematical representation used by JavaScript. If you want to perform arithmetic with these numbers in your question, it would be better to multiply them until they are whole numbers first, and then divide them.
Scale the numbers to become whole. Then modulus the result.
alert((5.30*10) % (0.1*10));
Now that you have read the article i commented, you should know the root of your problem.
You can partially work around that by scaling you floats...
Then just write a function which:
If its a float
Scale the Numbers
return a boolean representation of the divisibility of the number
function isDivisable(n, d) {
var ndI = 1 + "".indexOf.call(n, "."); //Index of the Number's Dot
var ddI = 1 + "".indexOf.call(d, "."); // Index of the Divisors Dot
if (ndI || ddI) { // IF its a float
var l = Math.max(("" + n).length - ndI, ("" + d).length - ddI); //Longest Decimal Part
var tmpN = (n * Math.pow(10, l)); //scale the float
var tmpD = (d * Math.pow(10, l));
return !~((tmpN % tmpD) - 1); //Substract one of the modulo result, apply a bitwise NOT and cast a boolean.
}
return !~((n % d) - 1); // If it isnt a decimal, return the result
}
console.log(isDivisable(5.30, 0.1));//true
Heres a JSBin
However...
As Integers are stored with 64bit precision, the maximum precision lies about (2^53),
and you will soon exceed the maximum precision when scaling larger numbers.
So it might be a good idea to get some sort of BigInteger Library for javascript
if you want to test floats for divisibility
To find if a number x is divisible by a number y you have to do x % y (modulo). If the result is 0, it is perfectly divisible, any other isn't.
You can get it by following:
var num = (5.30/0.1);
alert(num.toFixed(2));
this will give you 53.00.

Multiplication results in unusual decimal places [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is JavaScript’s Floating-Point Math Broken?
I have a strange mathematical problem during a multiplication in javascript.
$(parent).find('#id_deals-' + i + '-quantity').val()
result -> 10
$(parent).find('#id_deals-' + i + '-price').val()
result -> 3.99
Both above mulltiplied like this:
$(parent).find('#id_deals-' + i + '-price').val() * $(parent).find('#id_deals-' + i + '-quantity').val()
result --> 39.900000000000006
Why is this happening? and what can I do to limit the decimal places to 2 digits only?
Is it maybe because 10 has to be 10.0 ? But how do I convert my value to this format automatically before the actual multiplication?
Update:
According to syazdani's answer, I have tried to implement bigdecimal as suggested:
It is not well documented, but I got it working like this:
function run(opts) {
var bd = {"BigDecimal":BigDecimal, "BigInteger":BigInteger, "RoundingMode":RoundingMode};
var result;
var ops = {'*': "multiply", '/': "divide", '+': "add", '-': "subtract"};
var a = new bd.BigDecimal("" + opts.a);
var b = new bd.BigDecimal("" + opts.b);
var op = ops[opts.op];
if (op == "divide") {
return a.divide(b, 300, bd.RoundingMode.HALF_UP());
} else {
return a[op].call(a, b);
}
}
function multiply(a, b){
return run({"a":a,"b":b,"op":"*"});
}
If you are working with currency (as it seems that you are given the "price" id), you may be better served by using a so called Big Number library (such as this one: https://github.com/iriscouch/bigdecimal.js) for your math to control the math (round up vs round down, etc.). It takes a bit more work to get everything right, but it is worthwhile to avoid the Office Space math scenario.
All javascript number are IEEE-754 double precision floating points numbers. That means that they suffer from round-off errors and imprecision.
All numbers in javascript are floating point numbers, based on IEEE754.
If you want to format one as a string with a fixed number of digits after the dot, use
var formattedNumber = v.toFixed(2); // this makes a string

Handling Large Numbers in JavaScript

I just moved from Float to BigDecimal in my java code because I am dealing with large numbers.
Now i need to figure out how to handle these numbers in my JSP pages where I am using some validations on these numbers. I am currently handling the numbers in javascript in the following way:
var largeValue = parseFloat(document.getElementById('lValue').value);
and then I compare largeValue to other values.
(lvalue is id of a field where the large value is stored)
i need to know what is the limit of the 'parseFloat' method? and what would be a better way of comparing large numbers in javascript?
Regards,
Kaddy
I imagine it would be the same as the maximum value that a float can store, i.e., 1.7976931348623157e+308 according to this.
You can use Basenumber.js to handle with comparisons of BigDecimals in javascript. It's based on native BigInt so is lighter than others libs. Useful to lead with this types of problems:
console.log( 0.1 + 0.2 ); // = 0.30000000000000004
Here an example of how to use it
let x = Base("0.1");
let y = x.add(0.2);
console.log(y.toString()); // = '0.3'
<script src='https://cdn.jsdelivr.net/gh/AlexSp3/Basenumber.js#main/BaseNumber.min.js'></script>
Comparing numbers
let a = 0.99999999999999999999;
let b = 1;
console.log(a == b); // = true
let x = Base("0.99999999999999999999");
let y = Base("1");
console.log( x.equalTo(y) ); // => false
<script src='https://cdn.jsdelivr.net/gh/AlexSp3/Basenumber.js#main/BaseNumber.min.js'></script>

Converting a double to an int in Javascript without rounding

In C# the following code returns 2:
double d = 2.9;
int i = (int)d;
Debug.WriteLine(i);
In Javascript, however, the only way of converting a "double" to an "int" that I'm aware of is by using Math.round/floor/toFixed etc. Is there a way of converting to an int in Javascript without rounding? I'm aware of the performance implications of Number() so I'd rather avoid converting it to a string if at all possible.
Use parseInt().
var num = 2.9
console.log(parseInt(num, 10)); // 2
You can also use |.
var num = 2.9
console.log(num | 0); // 2
I find the "parseInt" suggestions to be pretty curious, because "parseInt" operates on strings by design. That's why its name has the word "parse" in it.
A trick that avoids a function call entirely is
var truncated = ~~number;
The double application of the "~" unary operator will leave you with a truncated version of a double-precision value. However, the value is limited to 32 bit precision, as with all the other JavaScript operations that implicitly involve considering numbers to be integers (like array indexing and the bitwise operators).
edit — In an update quite a while later, another alternative to the ~~ trick is to bitwise-OR the value with zero:
var truncated = number|0;
Similar to C# casting to (int) with just using standard lib:
Math.trunc(1.6) // 1
Math.trunc(-1.6) // -1
Just use parseInt() and be sure to include the radix so you get predictable results:
parseInt(d, 10);
There is no such thing as an int in Javascript. All Numbers are actually doubles behind the scenes* so you can't rely on the type system to issue a rounding order for you as you can in C or C#.
You don't need to worry about precision issues (since doubles correctly represent any integer up to 2^53) but you really are stuck with using Math.floor (or other equivalent tricks) if you want to round to the nearest integer.
*Most JS engines use native ints when they can but all in all JS numbers must still have double semantics.
A trick to truncate that avoids a function call entirely is
var number = 2.9
var truncated = number - number % 1;
console.log(truncated); // 2
To round a floating-point number to the nearest integer, use the addition/subtraction trick. This works for numbers with absolute value < 2 ^ 51.
var number = 2.9
var rounded = number + 6755399441055744.0 - 6755399441055744.0; // (2^52 + 2^51)
console.log(rounded); // 3
Note:
Halfway values are rounded to the nearest even using "round half to even" as the tie-breaking rule. Thus, for example, +23.5 becomes +24, as does +24.5. This variant of the round-to-nearest mode is also called bankers' rounding.
The magic number 6755399441055744.0 is explained in the stackoverflow post "A fast method to round a double to a 32-bit int explained".
// Round to whole integers using arithmetic operators
let trunc = (v) => v - v % 1;
let ceil = (v) => trunc(v % 1 > 0 ? v + 1 : v);
let floor = (v) => trunc(v % 1 < 0 ? v - 1 : v);
let round = (v) => trunc(v < 0 ? v - 0.5 : v + 0.5);
let roundHalfEven = (v) => v + 6755399441055744.0 - 6755399441055744.0; // (2^52 + 2^51)
console.log("number floor ceil round trunc");
var array = [1.5, 1.4, 1.0, -1.0, -1.4, -1.5];
array.forEach(x => {
let f = x => (x).toString().padStart(6," ");
console.log(`${f(x)} ${f(floor(x))} ${f(ceil(x))} ${f(round(x))} ${f(trunc(x))}`);
});
As #Quentin and #Pointy pointed out in their comments, it's not a good idea to use parseInt() because it is designed to convert a string to an integer. When you pass a decimal number to it, it first converts the number to a string, then casts it to an integer. I suggest you use Math.trunc(), Math.floor(), ~~num, ~~v , num | 0, num << 0, or num >> 0 depending on your needs.
This performance test demonstrates the difference in parseInt() and Math.floor() performance.
Also, this post explains the difference between the proposed methods.
What about this:
if (stringToSearch.IndexOfAny( ".,;:?!".ToCharArray() ) == -1) { ... }
I think that the easiest solution is using the bitwise not operator twice:
const myDouble = -66.7;
console.log(myDouble); //-66.7
const myInt = ~~myDouble;
console.log(myInt); //-66
const myInt = ~~-myDouble;
console.log(myInt); //66

Categories