I am building a simple crypto currency conversion page and it requires to divide and multiply rates in most cases.
The error I am getting is cases when i divide 1 by 5198000, I get 1.923816852635629e-7 in result
I realized that even the calculators gives that same out put.
How can I fix this in JavaScript?
The code below returns 1.923816852635629e-7 in console
var num1=1;
var num2=5198000;
var output=num1/num2;
console.log(output);
Is there a way to convert or bypass this.
This is scientific notation. The decimal format would be 0.0000001923816852635629. Code to generate this string to display in the UI for negative exponents is roughly:
var foo = 1/5198000; // scientific value
var sciStr= '' + foo; //cast scientific value to string
var w = '' + sciStr.substring(0, sciStr.indexOf('e')); // extract numerical value
var exp = Math.abs(parseInt(sciStr.substring(sciStr.indexOf('e')+1, sciStr.length))); // get absolute numerical exponent value
// write appropriate number of 0's
var expStr= '0.';
for (var i = 1; i < exp; i++) {
expStr+='0';
}
w = w.substring(0,1)+w.substring(2,w.length) // strip decimal from scientific value
console.log('the decimal form is:')
console.log(expStr+w) // outputs '0.0000001923816852635629'
You will need to modify this code to work for positive exponents (adding 0's at the end)
However, this should be stressed that the final result is a string, not a numerical value, so it won't be very useful if you need to perform further mathematical operations with it.
Related
I am trying to format numbers in JS to last two decimal.
For example 10100 becomes 101.00 - 606000 becomes 6,060.00 - 7600 becomes 76.00 and so on.
I have tried num.toFixed(2) but that was not of help. I also tried Number(10100).toLocaleString("es-ES", {minimumFractionDigits: 0}) but I end up with 10.100 so it seems off by one decimal.
So
num.toFixed(2)
What its doing its formatting,
Which would be 10.123 -> 10.12
what you should do is divide number by 100.
var number = 10100
number = number / 100
would be what you need.
I will approach this problem by using the help of strings.
Strings can be easily manipulated based on our requirements and then can be converted back to numbers. So, the solution goes like this
Convert the number to string
Manipulate the string to add a decimal before last two character
Convert the string back to number
const formatNumberToLastTwoDecimal = (number) => {
// Convert the number to String
const inputNumAsStr = number.toString();
// Manipulate the string and add decimal before two char
const updatedStr = `${inputNumAsStr.slice(0, -2)}.${inputNumAsStr.slice(-2)}`;
// Return by converting the string to number again
// Fix by 2 to stop parseFloat() from stripping zeroes to right of decimal
return new Number(parseFloat(updatedStr)).toFixed(2);
}
console.log(formatNumberToLastTwoDecimal(606000));
The most simplified way:
output = (number/100).toFixed(2)
And the complex way:
var c = 7383884
a = c.toString()
var output = parseFloat([a.slice(0, -2), ".",a.slice(-2)].join(''))
document.write(output)
I have to use very small numbers:
var x = 0.00000006;
When I run console.log(x), it shows:
6e-8
I don't want it to show 6e-8 , I want it to show 0.00000006.
Later I need to plot it on a graph, so I can't convert it to a string.
How to keep it a small number without converting it to a string or scientific notation?
You can convert it to "fixed" shape and get it to look like you want. Example would be:
var number = 6e-8; //this is your number
number = number.toFixed(8) //but since you won't always know how many decimal points you have you can use something like
number = number.toFixed(number.toString().split('-')[1]); //where you split your number, see how many decimals it has and pass that number to .toFixed method
This will be more correct,
only the last part after the e- notation is not the enough to be always the number you need to provide in toFixed
// containing Scientific Notation to a readable number string
export const convertScientificNotationNumber = (value) => {
const decimalsPart = value?.toString()?.split('.')?.[1] || '';
const eDecimals = Number(decimalsPart?.split('e-')?.[1]) || 0;
const countOfDecimals = decimalsPart.length + eDecimals;
return Number(value).toFixed(countOfDecimals);
//0.4210854715202004e-14).toFixed(30)
};
If the value of f5 cell in a Google Sheet is 1.1000 (a number formatted to 4 decimal places) and the value of f6 is = f5 * 1.073, how can I ensure I get the same result multiplying those values in Javascript, eg:
var original_value = 1.1000;
var derivative_value = original_value * 1.073;
Specifically, my question is - will the result of the Javascript multiplication (derivative_value) be the same as the result of the Google formula (f6)? And if not, how can I make it so that it is?
Context / What I've Tried
For context, this question is part of a larger question I am trying to resolve for which I have set up this JSFiddle.
The JSFiddle has an input for the original_value and an input for the multiplier.
It outputs the result to four decimal places and adds trailing zeros where required (this is the required format for the result).
It is an attempt to check that the Javascript code I am writing will produce the same result as the Google Sheet formula.
[ The JSFiddle has been updated to also log decimal.js results to the console for comparison ]
Edit
There was a suggestion to use decimal.js but I'm not sure how it would be applied - something like the following?
var original_value = new Decimal(1.1000);
// some different multipliers for testing
var multiplier_a = new Decimal(1.073);
var multiplier_b = new Decimal(1.1);
// some different results for testing
var derivative_value_a = original_value.times(multiplier_a).toString();
var derivative_value_b = original_value.times(multiplier_b).toString();
console.log(derivative_value_a); // 1.1803
console.log(derivative_value_b); // 1.21
Is that any more accurate than plain Javascript original_value * multiplier? More importantly for this question, will it always simulate the same result that a Google Sheet formula produces?
JavaScript is using so called double precision float format (64 bit)- https://tc39.github.io/ecma262/#sec-terms-and-definitions-number-value
Google Sheets seem to use the same format, you can test it by =f6*1E13 - round(f6*1E13) to see that f6 is not STORED as a fixed number format, only FORMATTED
see Number.toFixed how to FORMAT numbers in Javascript
to generate some test data:
[...Array(10)].forEach(() => {
const f5 = 1.1
const x = Math.random() / 100
const f6 = f5 * x
console.log(x, f6.toFixed(4))
})
and compare in Google Sheet:
https://docs.google.com/spreadsheets/d/1jKBwzM41nwIEyatLUHEUwteK8ImJg334hzJ8nKkUZ5M/view
=> all rounded numbers are equal.
P.S.: you need to copy the console output, paste into the Sheet, use the menu item Data > Split text into columns... > Space, then multiply by 1.1 in 3rd column and finally format all numbers
After revisiting this I have updated the jsFiddle.
The main components of what I believe are a satisfactory solution are:
Convert both original_value and multiplier to decimal.js objects.
Do the multiplication using the decimal.js times method.
Do the rounding using the decimal.js toDecimalPlaces method.
Use the argument values (4,7) to define 4 decimal places with ROUND_HALF_CEIL rounding, equivalent to Math.round (reference)
For example:
var my_decimal_js_value = new Decimal(original_value).times(new Decimal(multiplier)).toDecimalPlaces(4, 7);
In order to add any necessary trailing zeros to the result, I use:
function trailingZeros(my_decimal_js_value) {
var result = my_decimal_js_value;
// add zeros if required:
var split_result = result.toString().split(".");
// if there are decimals present
if (split_result[1] != undefined) {
// declare trailing_zeros;
var trailing_zeros;
// get the amount of decimal numbers
decimals_present = split_result[1].length;
// if one decimal number, add three trailing zeros
if (decimals_present === 1) {
trailing_zeros = "000";
result += trailing_zeros;
}
// if two decimal numbers, add two trailing zeros
else if (decimals_present === 2) {
trailing_zeros = "00";
result += trailing_zeros;
}
// if three decimal numbers, add one trailing zero
else if (decimals_present === 3) {
trailing_zeros = "0";
result += trailing_zeros;
}
// if four decimal numbers, just convert result to string
else if (decimals_present === 4) {
result = result.toString();
}
}
// if there are no decimals present, add a decimal place and four zeros
else if (split_result[1] === undefined) {
trailing_zeros = ".0000";
result += trailing_zeros;
}
return result;
}
I am still not absolutely certain that this mimics the Google Sheet multiplication formula, however using decimal.js, or another dedicated decimal library, seems to be the preferred method over plain JavaScript (to avoid possible rounding errors), based on posts such as these:
http://www.jacklmoore.com/notes/rounding-in-javascript
Is floating point math broken?
https://spin.atomicobject.com/2016/01/04/javascript-math-precision-decimals
I have a value fetched from the database, it's like:
4.5 which should be 4.500
0.01 which should be 0.010
11 which should be 11.000
so I used this piece of code
sprintf("%.3f",(double)$html['camp_cpc'])
But here arised another problem. If $html['camp_cpc'] = '4.5234', then also it displays 4.523 instead of original value 4.5234
Also for other values with larger decimal like 0.346513, its only showing up to 0.346.
How can I solve this problem in JavaScript also?
Floats 4.5 and 4.500 correspond to the same number, so they cannot (and should not) be used/stored in a way that preserves the different representation. If you need to preserve the original representation given by a user, you need to store this field as a list (string) and convert to a float whenever you need the float value
In Javascript at least, this is an implementation of what I think you want:
function getValue(x, points) {
var str = x.toString();
// Convert to string
var idx = str.indexOf(".");
// If the number is an integer
if(!~idx) return str + "." + "0".repeat(points);
// Get the tail of the number
var end = str.substr(idx+1);
// If the tail exceeds the number of decimal places, return the full string
if(end.length > points) return str;
// Otherwise return the int + the tail + required number of zeroes
return str.substr(0, idx) + "." + end.substr(0, points) + "0".repeat(points-end.length);
}
console.log(getValue(4.5, 3)); //4.500
console.log(getValue(0.01, 3)); //0.010
console.log(getValue(11, 3)); //11.000
Working demo (Makes use of ES6 String.repeat for demonstration purposes)
The important thing to note here is that this is string manipulation. Once you start to say "I want the number to look like..." it's no longer a number, it's what you want to show the user.
This takes your number, converts it to the string and pads the end of the string with the appropriate number of zeroes. If the decimal exceeds the number of places required the full number is returned.
In PHP, use %0.3f — and you don't need to cast as (double)
<?php
echo sprintf("%0.3f", 4.5); // "4.500"
echo sprintf("%0.3f", 4.5234); // "4.523"
If you want to display 4 decimal places, use %0.4f
echo sprintf("%0.4f", 4.5); // "4.5000"
echo sprintf("%0.4f", 4.5234); // "4.5234"
To do this in JavaScript
(4.5).toFixed(3); // "4.500"
It could look sth. like this:
var n = [4.5234, 0.5, 0.11, 456.45];
var temp_n;
for(var i = 0; i < n.length; i++) {
temp_n = String(n[i]).split(".");
if(temp_n[1] == null || temp_n[1].length < 3) {
n[i] = n[i].toFixed(3);
}
}
toFixed() function responding differently for float values.
For Example:
var a = 2.555;
var b = 5.555;
console.log(a.toFixed(2)); /* output is 2.56 */
console.log(b.toFixed(2)); /* output is 5.55 */
For 2.555/3.555 results are (2.56/3.56)
and
For other values(not sure for all values) it is showing #.55 (# refers to any number)
I am confused can any one help me out.
Thanks in advance.
Javascript uses a binary floating point representation for numbers (IEEE754).
Using this representation the only numbers that can be represented exactly are in the form n/2m where both n and m are integers.
Any number that is not a rational where the denominator is an integral power of two is impossible to represent exactly because in binary it is a periodic number (it has infinite binary digits after the point).
The number 0.5 (i.e. 1/2) is fine, (in binary is just 0.1₂) but for example 0.55 (i.e. 11/20) cannot be represented exactly (in binary it's 0.100011001100110011₂… i.e. 0.10(0011)₂ with the last part 0011₂ repeating infinite times).
If you need to do any computation in which the result depends on exact decimal numbers you need to use an exact decimal representation. A simple solution if the number of decimals is fixed (e.g. 3) is to keep all values as integers by multiplying them by 1000...
2.555 --> 2555
5.555 --> 5555
3.7 --> 3700
and adjusting your computation when doing multiplications and divisions accordingly (e.g. after multiplying two numbers you need to divide the result by 1000).
The IEEE754 double-precision format is accurate with integers up to 9,007,199,254,740,992 and this is often enough for prices/values (where the rounding is most often an issue).
Try this Demo Here
function roundToTwo(num) {
alert(+(Math.round(num + "e+2") + "e-2"));
}
roundToTwo(2.555);
roundToTwo(5.555);
toFixed() method depending on Browser rounds down or retain.
Here is the solution for this problem, check for "5" at the end
var num = 5.555;
var temp = num.toString();
if(temp .charAt(temp .length-1)==="5"){
temp = temp .slice(0,temp .length-1) + '6';
}
num = Number(temp);
Final = num.toFixed(2);
Or reusable function would be like
function toFixedCustom(num,upto){
var temp = num.toString();
if(temp .charAt(temp .length-1)==="5"){
temp = temp .slice(0,temp .length-1) + '6';
}
num = Number(temp);
Final = num.toFixed(upto);
return Final;
}
var a = 2.555;
var b = 5.555;
console.log(toFixedCustom(a,2));
console.log(toFixedCustom(b,2));