When I write a float to a buffer, it does not read back the same value:
> var b = new Buffer(4);
undefined
> b.fill(0)
undefined
> b.writeFloatBE(3.14159,0)
undefined
> b.readFloatBE(0)
3.141590118408203
>
(^C again to quit)
>
Why?
EDIT:
My working theory is that because javascript stores all numbers as double precision, it's possible that the buffer implementation does not properly zero the other 4 bytes of the double when it reads the float back in:
> var b = new Buffer(4)
undefined
> b.fill(0)
undefined
> b.writeFloatBE(0.1,0)
undefined
> b.readFloatBE(0)
0.10000000149011612
>
I think it's telling that we have zeros for 7 digits past the decimal (well, 8 actually) and then there's garbage. I think there's a bug in the node buffer code that reads these floats. That's what I think. This is node version 0.10.26.
Floating point numbers ("floats") are never a fully-accurate representation of a number; this is a common feature that is seen across multiple languages, not just JavaScript / NodeJS. For example, I encountered something similar in C# when using float instead of double.
Double-precision floating point numbers are more accurate and should better meet your expectations. Try changing the above code to write to the buffer as a double instead of a float:
var b = new Buffer(8);
b.fill(0);
b.writeDoubleBE(3.14159, 0);
b.readDoubleBE(0);
This will return:
3.14159
EDIT:
Wikipedia has some pretty good articles on floats and doubles, if you're interested in learning more:
http://en.wikipedia.org/wiki/Floating_point
http://en.wikipedia.org/wiki/Double-precision_floating-point_format
SECOND EDIT:
Here is some code that illustrates the limitation of the single-precision vs. double-precision float formats, using typed arrays. Hopefully this can act as proof of this limitation, as I'm having a hard time explaining in words:
var floats32 = new Float32Array(1),
floats64 = new Float64Array(1),
n = 3.14159;
floats32[0] = n;
floats64[0] = n;
console.log("float", floats32[0]);
console.log("double", floats64[0]);
This will print:
float 3.141590118408203
double 3.14159
Also, if my understanding is correct, single-precision floating point numbers can store up to 7 total digits (significant digits), not 7 digits after the decimal point. This means that they should be accurate up to 7 total significant digits, which lines up with your results (3.14159 has 6 significant digits, 3.141590118408203 => first 7 digits => 3.141590 => 3.141590 === 3.14159).
readFloat in node is implemented in c++ and bytes are interpreted exactly the way your compiler stores/reads them. I doubt there is a bug here. What I think is that "7 digits" is incorrect assumption for float. This answer suggest 6 digits (and it's the value of std::numeric_limits<float>::digits10 ) so the result of readFloatBE is within expected error
Related
Will I possibly loose any decimal digits (precision) when multiplying Number.MAX_SAFE_INTEGER by Math.random() in JavaScript?
I presume I won't but it'd be nice to have a credible explanation as to why 😎
Edited, In layman terms, we're dealing with two IEEE 754 double-precision floating-point numbers, one is the maximal integer (for double-precision), the other one is fractional with quite a few digits after a decimal point. What if (say) I first converted them to quadruple-precision format, then multiplied, and then converted the product back to double-precision, would the result be any different?
const max = Number.MAX_SAFE_INTEGER;
const random = Math.random();
console.log(`\
MAX_SAFE_INTEGER: ${max}, \
random: ${random}, \
product: ${max * random}`);
For more elaborate examples, I use it to generate BigInt random numbers.
Your implementation should be safe - in theory, all numbers between 0 and MAX_SAFE_INTEGER should have a possibility of appearing, if the engine implementing Math.random uses a completely unbiased algorithm.
But an absolutely unbiased algorithm is not guaranteed by the specification - the numbers chosen are meant to be psuedo random, not truly, completely random. (does such a thing even exist? it's debatable...) Modern versions V8 and some other implementations use an algorithm with a period on the order of 2 ** 128, larger than MAX_SAFE_INTEGER (2 ** 53 - 1) - but it'd be completely plausible for other implementations (especially older ones) to have a much smaller period, resulting in certain integers within the range being picked much more often than others.
If this is important for your script (which is pretty unlikely in most situations, I'd think), you might consider using a higher-quality random generatior than Math.random - but it's almost certainly not worth worrying about.
What if (say) I first converted them to quadruple-precision format, then multiplied, and then converted the product back to double-precision, would the result be any different?
It could be in cases where the rounding behaves differently between multiplying two doubles vs converting quadruple to double, but the main problem remains the same. The spacing between representable doubles in the range from 2n to 2n+1 is 2n−52. So between 252 and 253 only whole numbers can be represented, between 251 and 252 only every 0.5 can be represented, etc.
If you want more precision you could try decimal.js. The library is included on that documentation page so you can try these out in your console.
Number.MAX_SAFE_INTEGER*.9
8106479329266892
new Decimal(Number.MAX_SAFE_INTEGER).mul(new Decimal(0.9)).toString()
"8106479329266891.9"
Both answers are correct, but I couldn't help running this little experiment in C#, where double is the same thing as Number in JavaScript (fiddle):
using System;
public class Program
{
public static void Main()
{
const double MAX_SAFE_INT = 9007199254740991;
Decimal maxD = Convert.ToDecimal(MAX_SAFE_INT.ToString());
var rng = new Random(Environment.TickCount);
for (var i = 0; i < 1000; i++)
{
double random = rng.NextDouble();
double product = MAX_SAFE_INT * random;
// converting via string to workaround the "15 significant digits" limitation for Decimal(Double)
Decimal randomD = Decimal.Parse(String.Format("{0:F18}", random));
Decimal productD = maxD * randomD;
double converted = Convert.ToDouble(productD);
if (Math.Floor(converted) != Math.Floor(product))
{
Console.WriteLine($"{maxD}, {randomD, 22}, products: decimal {productD, 32}, converted {converted, 20}, original {product, 20}");
}
}
}
}
As far as I'm concerned, I'm still getting the desired distribution of the random numbers within the 0 - 9007199254740991 range.
Here is a JavaScript playground code to check for possible recurrences.
I have this Java code:
nextDouble = 0.2515933907977884;
long numerator = (long) (nextDouble * (1L << 53));
I would like to be able to produce the same output this line produces in Java but within JavaScript.
nextDouble = 0.2515933907977884;
const numerator = nextDouble * (1 << 53);
Has anybody got an idea for how to replicate a long within JavaScript ? I know there is BigInt in JavaScript but thing is, it doesn't support floating point numbers, so I am a bit stuck on what to do. Does anybody know any interesting libraries, that could solve this issue ?
Thank you in advance !
The problem is what 1<<53 does in javascript. It doesn't do what you think it does.
Here, try this in the console:
1<<30
1073741824
// okay.. looks good
1<<31
> -2147483648
// a negative num.. wha??
1<<32
> 1
// WHAA????????
1<<53
> 2097152
// That seems VERY low to me
1<<21
> 2097152
// How is that the same? as 1<<53??
numbers in javascript are forced into being doubles, and doing bit shifts on a double is utterly ridiculous. Javascript nevertheless lets you, because, well, javascript. When you do silly things in javascript, javascript will give you silly answers, and in that way javascript is rather worthless - programmers doing crazy stuff that cannot reasonably be interpreted as having any particular meaning should be answered with a clear error and not a wild stab in the dark. But that's just how javascript is. The usual way to deal with this crazy behaviour is to never ask javascript silly things, as it will give you silly answers. Such as 1<<32 being 1*.
You may be wondering 'but how is asking to bit shift 1 by 53 positions 'crazy'? - and the answer is, that bit shifts, given that they make no sense on doubles, are interpreted as: "You wish to emulate 32-bit signed int behaviour", and that is exactly what javascript does, notably including the weirdish java/C-ism that only the bottom 5 bits of the number on the RHS count. In other words, <<32 is the same thing as <<0 - after all, the bottom 5 bits of 32.. is 0. Said differently, take the right hand side number, divide it by 32, toss the result, keep the remainder ('modulo'). 32 divided by 32 leaves a remainder of 0. 53 divided by 32 leaves a remainder of 21, and that's why 1<<53 in javascript prints 2097152.
So, in javascript your code is effectively doing the double multiplied by 2 to the 21st power, or theDouble * 2097152, whereas in java it is doing the double multiplied by 2 to the 53rd power, or theDouble * 9007199254740992.
Rather obviously then your answers are wildly different.
The fix seems trivial. 1<<53 may look like a nice way to convey the notion of 2 to 53rd power or in bits, a 1 bit, followed by 53 zeroes, but as syntax goes it just does not work that way in javascript. You can't use that syntax for this purpose. Try literally 9007199254740992.
var d = 0.2515933907977884;
const n = d * 9007199254740992;
n
> 2266151802091599
so that works.
If you have a need to derive the value 9007199254740992 from the value 53:
Math.pow(2, 53)
> 9007199254740992
note that you're dancing on the edge of disaster here. standard IEEE doubles use 53 bits for the exponent, so you're at the very edges. Soon you'll get into the territory where 'x + 1' is equal to 'x' because the gap between representable numbers is larger than 1. You'll need to get cracking on BigInt if you want to move away from the precipice.
*) It is specced behaviour. But surely you agree this is highly surprising. How many people do you know that just know off-hand that javascripts << is specced to convert to a 32-bit signed integer, take the RHS and modulo 32 it, and then operate, and then convert back to double afterwards?
I have a problem in precision in the last digit after the comma.The javascript code generates one less Digit in compare with the C# code.
Here is the simple Node.js code
var seed = 45;
var x = Math.sin(seed) * 0.5;
console.log(x);//0.4254517622670592
Here is the simple C# code
public String pseudorandom()
{
int seed = 45;
double num = Math.Sin(seed) * (0.5);
return num.ToString("G15");//0.42545176226705922
}
How to achieve the same precision?
The JavaScript Number type is quite complex. It looks like floating point number will probably be like IEEE 754-2008 but some aspects are left to the implementation. See http://www.ecma-international.org/ecma-262/6.0/#sec-number-objects sec 12.7.
There is a note
The output of toFixed may be more precise than toString for some
values because toString only prints enough significant digits to
distinguish the number from adjacent number values. For example,
(1000000000000000128).toString() returns "1000000000000000100", while
(1000000000000000128).toFixed(0) returns "1000000000000000128".
Hence to get full digit accuracy you need something like
seed = 45;
x = Math.sin(seed) * 0.5;
x.toFixed(17);
// on my platform its "0.42545176226705922"
Also, note the specification for how the implementation of sin and cos allow for some variety in the actual algorithm. It's only guaranteed to within +/- 1 ULP.
Using java the printing algorithm is different. Even forcing 17 digits gives the result as 0.42545176226705920.
You can check you are getting the same bit patterns using x.toString(2) and Double.doubleToLongBits(x) in Java.
return num.ToString("G15");//0.42545176226705922
actually returns "0.425451762267059" (no significant digit + 15 decimal places in this example), and not the precision shown in the comment after.
So you would use:
return num.ToString("G16");
to get "0.4254517622670592"
(for your example - where the significant digit is always 0) G16 will be 16 decimal places.
I have this formula on excel
=(1130000000000*F11^1.85)/(F19^1.85*(F13*(1-2/F15))^4.8655)
when
F11 = q
F19 = 150 (Constant)
F13 = d
F15 = sdr
I convert it to this
Math.round((1130000000000*Math.pow(q,1.85))/(Math.pow(150,1.85)*Math.pow(d*(1-2/sdr)),4.8655))
but the results are wrong
when
q = 120
d = 200
sdr = 17
the result should be 8.76
but I am getting long numbers
any help ?
Thanks
From YUI blog
JavaScript has a single number type: IEEE 754 Double Precision floating point. Having a single number type is one of JavaScript’s best features. Multiple number types can be a source of complexity, confusion, and error. A single type is simplifying and stabilizing.
Unfortunately, a binary floating point type has some significant disadvantages. The worst is that it cannot accurately represent decimal fractions, which is a big problem because humanity has been doing commerce in decimals for a long, long time. There would be advantages to switching to a binary-based number system, but that is not going to happen. As a consequence, 0.1 + 0.2 === 0.3 is false, which is the source of a lot of confusion.
http://www.yuiblog.com/blog/2009/03/10/when-you-cant-count-on-your-numbers/
Completely ignore my previous answer, although it is a problem which you will definitely encounter should you continue with these large numbers, your actual issue is a misplaced bracket in your code. If you use this (simply replaced variable names with values):
Math.round((1130000000000*Math.pow(120,1.85))/(Math.pow(150,1.85)*Math.pow((200*(1-2/17)),4.8655)))
It returns 9 (a rounded 8.76), the bracket you misplaced is around the 1-2 mark.
For future reference, the largest number Javascript can comprehend without fault is +/- 9007199254740992.
References:
What is JavaScript's highest integer value that a Number can go to without losing precision?
ECMA-262 - The Number Type
I've used Math.pow() to calculate the exponential value in my project.
Now, For specific values like Math.pow(3,40), it returns 12157665459056929000.
But when i tried the same value using a scientific Calculator, it returns 12157665459056928801.
Then i tried to traverse the loop till the exponential value :
function calculateExpo(base,power){
base = parseInt(base);
power = parseInt(power);
var output = 1;
gameObj.OutPutString = ''; //base + '^' + power + ' = ';
for(var i=0;i<power;i++){
output *= base;
gameObj.OutPutString += base + ' x ';
}
// to remove the last comma
gameObj.OutPutString = gameObj.OutPutString.substring(0,gameObj.OutPutString.lastIndexOf('x'));
gameObj.OutPutString += ' = ' + output;
return output;
}
This also returns 12157665459056929000.
Is there any restriction to Int type in JS ?
This behavior is highly dependent on the platform you are running this code at. Interestingly even the browser matters even on the same very machine.
<script>
document.write(Math.pow(3,40));
</script>
On my 64-bit machine Here are the results:
IE11: 12157665459056928000
FF25: 12157665459056929000
CH31: 12157665459056929000
SAFARI: 12157665459056929000
52 bits of JavaScript's 64-bit double-precision number values are used to store the "fraction" part of a number (the main part of the calculations performed), while 11 bits are used to store the "exponent" (basically, the position of the decimal point), and the 64th bit is used for the sign. (Update: see this illustration: http://en.wikipedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg)
There are slightly more than 63 bits worth of significant figures in the base-two expansion of 3^40 (63.3985... in a continuous sense, and 64 in a discrete sense), so hence it cannot be accurately computed using Math.pow(3, 40) in JavaScript. Only numbers with 52 or fewer significant figures in their base-two expansion (and a similar restriction on their order of magnitude fitting within 11 bits) have a chance to be represented accurately by a double-precision floating point value.
Take note that how large the number is does not matter as much as how many significant figures are used to represent it in base two. There are many numbers as large or larger than 3^40 which can be represented accurately by JavaScript's 64-bit double-precision number values.
Note:
3^40 = 1010100010111000101101000101001000101001000111111110100000100001 (base two)
(The length of the largest substring beginning and ending with a 1 is the number of base-two significant figures, which in this case is the entire string of 64 digits.)
Haskell (ghci) gives
Prelude> 3^40
12157665459056928801
Erlang gives
1> io:format("~f~n", [math:pow(3,40)]).
12157665459056929000.000000
2> io:format("~p~n", [crypto:mod_exp(3,40,trunc(math:pow(10,21)))]).
12157665459056928801
JavaScript
> Math.pow(3,40)
12157665459056929000
You get 12157665459056929000 because it uses IEEE floating point for computation. You get 12157665459056928801 because it uses arbitrary precision (bignum) for computation.
JavaScript can only represent distinct integers to 253 (or ~16 significant digits). This is because all JavaScript numbers have an internal representation of IEEE-754 base-2 doubles.
As a consequence, the result from Math.pow (even if was accurate internally) is brutally "rounded" such that the result is still a JavaScript integer (as it is defined to return an integer per the specification) - and the resulting number is thus not the correct value, but the closest integer approximation of it JavaScript can handle.
I have put underscores above the digits that don't [entirely] make the "significant digit" cutoff so it can be see how this would affect the results.
................____
12157665459056928801 - correct value
12157665459056929000 - closest JavaScript integer
Another way to see this is to run the following (which results in true):
12157665459056928801 == 12157665459056929000
From the The Number Type section in the specification:
Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the Number type ..
.. but not all integers with large magnitudes are representable.
The only way to handle this situation in JavaScript (such that information is not lost) is to use an external number encoding and pow function. There are a few different options mentioned in https://stackoverflow.com/questions/287744/good-open-source-javascript-math-library-for-floating-point-operations and Is there a decimal math library for JavaScript?
For instance, with big.js, the code might look like this fiddle:
var z = new Big(3)
var r = z.pow(40)
var str = r.toString()
// str === "12157665459056928801"
Can't say I know for sure, but this does look like a range problem.
I believe it is common for mathematics libraries to implement exponentiation using logarithms. This requires that both values are turned into floats and thus the result is also technically a float. This is most telling when I ask MySQL to do the same calculation:
> select pow(3, 40);
+-----------------------+
| pow(3, 40) |
+-----------------------+
| 1.2157665459056929e19 |
+-----------------------+
It might be a courtesy that you are actually getting back a large integer.