Good day,
I am still learning JS and HTML and I noticed something quite interesting for me
I am using Google Geocoding scripts and created an on click event on the map to retrieve the GPS co-ordinates,
function onClickCallback(event){
var str = event.latLng.toString().slice(1,-1).split(',', 2);
var lat1 = parseFloat(str[0]).toFixed(5);
var lng1 = parseFloat(str[1]).toFixed(5);
var latlng1 = new google.maps.LatLng(lat1,lng1).toString().slice(1,-1);
document.getElementById('latlng').value = latlng1;
this works perfectly for my needs however for some odd reason the second part "lng1" does not round down as expected and as an example the below is the result
-25.3341, 27.64984000000004 or -25.34403, 27.97393999999997
as the first part 'lat1' works fine what is the reason or cause for the second part 'lng1' not rounding and only displaying the first 5 decimals and how can I fix it
The problem is most likely a combination of type conversion and javascript's built in floating point number representation.
When you call toFixed() your number is actually converted to a string with the desired number of decimals. google.maps.LatLng() expects two numbers but, since you're not getting any errors, is also fine receiving string representations of numbers instead.
Internally, I assume google.maps.LatLng() converts the lat1 and lng1 arguments to numbers again. Since the way javascript represents numbers often results in small rounding errors, the toString() gets lng1, which is now a number again and likely slightly different than what toFixed() originally returned, and converts it back to a string.
If you want to be able to output nice numbers, you could postpone the toFixed() calls until the end:
...
var lat1Formatted = parseFloat(latlng1.split(', ')[0]).toFixed(5);
var lng1Formatted = parseFloat(latlng1.split(', ')[1]).toFixed(5);
document.getElementById('latlng').value = lat1Formatted + ', ' + lng1Formatted;
Related
I'm using this BigInteger.js for some calculations:
let myBigInt = bigInt(20).pow(200) // gets 160693804425899027554196209234116260252220299378279283530137600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I'd like to apply the logarithm to the big integer but in the docs I could not find any matching function. How can I implement a log(baseN, valueX) function for the BigInteger.js library?
Note: let myLogarithm = myBigInt.log(baseN) is not a valid implementation.
Note: After a lot of try&error I did found a working solution my own and I will post it here because I'm pretty sure there are a few more people then me that also gots faced with the same issue right there. So I hope, I could help :)
Have a look at wikipedia, as I did because theres a very nice article about baseConversion.
Below you can find a function for Math.log(base, value) that is able to calculate the log(base) from a value.
Math.log = (function() {
var log = Math.log;
return function(base, n) {
return log(n)/(base ? log(base) : 1);
};
})();
To calculate the logarithmToBaseN for bigInt-values just use this line of code:
let logarithmToBaseN = (myBigInt.toString().length * Math.log(baseN, 10) + Math.log(baseN, parseFloat("0." + myBigInt))) - 1);
Edit: This soltuion is a tiny workaround bacause parseFloat("0." + myBigInt) converts a big value like 100000 to a really small one like 0.100000,... what causes that it will be in integer precision.
According to #Jonas W's comment: The solution is very accurate for lower bases like (5, 10, ...) combined with low values like 10, 1000, 100000 - but for really big values like bigInt(20).pow(200) is it not.
Note: Using parseFloat (IEEE 754 double precision floating-point) means, you have a maximum of 52 bits of precision, which is a bit more than 15 decimal places. After that - the accuracy will be killed.
Note: For really big values bigInt(20).pow(200) combined with really big Bases like 100*(and more) it seems to be pretty accurate again.
Greetings, jonas.
I'm dealing with relatively small and simple numbers. I first tried to do the rounding (2 signs after digit) with infamous toFixed. It's a known issue: sometimes it works incorrectly. But what struck me is the fact that it also works inconsistently:
(0.395).toFixed(2); // "0.40"
(0.295).toFixed(2); // "0.29"
These numbers are very similar, 3 signs after digit and yet different behavior.
So, I decided to switch to using Math.round. Shortly, I encountered another problem:
Math.round(0.35055 * 10000) / 100; // produces 35.05 instead of 35.06
Is Math.round also problematic? Then, what method should be used?
Unfortunately JavaScript is known to have such precision issues, issues that are better explained in the following question: Is floating point math broken?, as pointed in the comments.
If you require a greater degree of numerical accuracy, I would suggest you to use a library such as BigNumber, which also comes with its own toFixed method.
Your example would look something like this:
var a = new BigNumber('0.35055');
a = a.times(10000)
a = a.dividedBy(100)
console.log(a.toFixed(2)); //would log "35.06"
For brevity you can also chain the operations, like this: a.times(10000).dividedBy(100).toFixed(2)
I think this is working as designed. Keep in mind these numbers are stored in base 2, so there is a loss of precision when converting to and from base 10. And you have to look at these conversions if you want to understand why it looks inconsistent. If you have a fixed number of decimals that you want to keep precisely, you can use integers for operations and convert only for display.
I have a JavaScript calculator which uses the Math.cbrt() function. When I calculate the cube root of 125 it returns 4.999999999999999. I understand that I could use Math.round() to round any answers that this function returns to integer values, but I do not want to do that exactly. Is there a way to use this if and only if the result of calculation is some number followed by a string of 9s (or something similar like 4.99999998 perhaps) after the decimal?
What you are dealing with is the frustration of floating point numbers in computing. See the Floating Point Guide for more information on this critical topic.
The short version:
Certain non-integer values cannot be represented accurately by computers, so they store a value that is "near enough". Just try evaluating 3.3 / 3 in your favourite REPL.
Say what?!
Computers are supposed to be perfect at this numbers/math thing, right? Can I trust any answer they give me?
Yes, for integers, they are pretty much perfect. But for non-integer calculations, you should assume that answers won't be exact, and account for these floating point errors.
The solution in Javascript
In newer versions of Javascript, you have a defined constant Number.EPSILON, which is the smallest difference between the actual number and the approximation that it can actually store.
Using this, you can multiply that constant by the result you get and add it to the result and you should get the exact value you require.
function cbrt(n) {
return Math.cbrt(n) + (Number.EPSILON * Math.cbrt(n));
}
Alternatively, you can use the rounding behaviour of the .toFixed() method on numbers together with the parseFloat() function if you only care about numbers up to a certain number of decimal places (less than 20).
function num(n, prec) {
if (prec === void 0) prec = 8; // default to 8 decimal places
return parseFloat(n.toFixed(prec));
}
var threshold = 0.999; // set to whatever you want
var fraction = result % 1;
if (fraction >= threshold) {
result = Math.round(result);
}
I am trying to write some code in javascript to calculate trig functions, inverse trig functions, and hyperbolic trig functions with imaginary numbers. I have the sin, cos, sinh, and cosh working well. However, I am having some trouble getting my solutions for others to match the only verification that I can find at this site.
For example, below is the code for asin(x+yi). I am using the formula located here along with the definitions for modulus and argument found there as well. It has no errors, but doesn't match the results from the site I cited. What am I doing wrong?
asin(z)=-i*ln(iz+sqrt(1-z^2))
var id1=SquareComplex (window[id].Solution_real, window[id].Solution_imag);
var real=1-window[id1].Solution_real;
var imag=window[id1].Solution_imag;
var id2=SquareRoot(real, imag);
imag=window[id].Solution_real+window[id2].Solution_imag;
real=-window[id].Solution_imag+window[id2].Solution_real;
var modulus=Math.sqrt(real^2+imag^2);
var argument=Math.atan2(imag,real);
var Solution_imag=-Math.log(modulus);
var Solution_real=argument;
This code is intended to work in several steps. The first line calls a function that squares the complex number z. The second and third lines subtract the result from the number 1. The fourth line calls a function to take the square root of the complex number. The fifth and sixth lines add the results of the previous actions to the result of multiplying the complex number by i. The remaining lines get the modulus and argument of those results, take the natural logarithm, and multiply it by a negative i.
Your first three lines are:
var id1=SquareComplex (window[id].Solution_real, window[id].Solution_imag);
var real=1-window[id1].Solution_real;
var imag=window[id1].Solution_imag;
assuming that id is your initial z then this is not calculating the real and imaginary parts of 1-z^2 as I believe it is indtended to. The reason being that the imaginary part isn't being subtracted.
Try it with
var imag = -window[id1].Solution_imag;
and see if that helps. I can't guarantee there aren't any more errors in it but I'd suggest just going through and being really careful about making sure each line does what it should.
You may be interested in math.js, which comes with support for complex numbers for all functions including trigonometry:
var value = math.complex(2, 3);
var ans = math.asin(value);
Or using the expression parser:
var ans = math.eval('asin(2 + 3i)');
I'm attempting to perform the following calculation in Javascript:
e^x / (1 + e^x)
where x is a long floating point number.
In this instance, I require accuracy to at least the 10th decimal place.
I've been using BigDecimal to accurately handle the floating point numbers, as suggested at The Floating Point Guide.
My first attempt of:
var foo = new BigDecimal(myVeryLongFloatingPoint)
var bar = Math.exp(foo);
var spam = bar.divide(bar.add(new BigDecimal("1")));
led to the error (where xxxxx is the floating point number):
TypeError: Object xxxxx has no method 'add'
So I attempted to tried convert bar into a BigDecimal object:
var foo = new BigDecimal(myVeryLongFloatingPoint)
var bar = new BigDecimal(Math.exp(foo));
var spam = bar.divide(bar.add(new BigDecimal("1")));
which in turn leads to the error (where xxxxx is the floating point number):
BigDecimal(): Not a number: xxxxx
Where am I going wrong?
Is this a sensible approach to handling this kind of calculation with floating points where a high degree of precision is required?
You should pass strings to BigDecimal:
var bar = new BigDecimal(Math.exp(foo).toString());
There are a few mathematical approaches that might be useful. If x is positive and reasonably large, then you're taking the ratio of two large number and this will reduce your final precision. Instead, you might:
Use 1./(1. + e^(-x)) instead.
For large x, this is approximately 1.-e^(-x), and the bigger x is, the better the approximation (e.g., if x=100, then your error would be in the 86th digit).
(Honestly, one should verify this before using it, I'm just going of off memory here an not writing anything down, but if this looks useful, I could grab a pencil...)
Math.exp only works on normal Numbers and cannot operate on BigDecimals. Math.exp is probably converting foo to NaN (or something like that) before continuing.
You should look for an exponentiation method inside your BigDecimal class. I looked at the source and I think there is a BigDecimal.pow method you could use instead.