I am trying to Math.floor a scientific notation, but at one point the number gets too big and my current method doesn't work anymore. This is what I am using atm
var nr = (number+"").length - 4;
if( nr > 1 ) {
nr = Math.pow( 10, nr );
number= Math.floor(number/nr)*nr;
number= number.toExponential(3);
}
When it becomes a scientific notation by default, I think that's e20+, than my .length method doesn't work anymore since the length it returns isn't accurate. I can think of a work around, and that's to find out the number after e, and update my nr to Math.floor it properly, but it seems like so much work to do something so simple. Here's an example number 8.420960987929105e+79 I want to turn this into 8.420e+79, is there a way I can Math.floor the third decimal point always, no matter what the number is? As it stands when I use toExponential(3) it always rounds the number. My numbers can get as high as e+200 easily, so I need an easier way of doing what I'm currently doing.
Edit: managed to find a work around that works besides Connor Peet's answer for anyone who wants extra options
var nr = 8.420960987929105e+79+"";
var nr1 = nr.substr(0,4);
var nr2 = nr.substr(4, nr.length);
var finalNr = Number(nr1 + 0 + nr2).toExponential(3);
This way is more of a hack, it adds a 0 after the 4th number so when toExponential rounds it up, it gets 'floored' pretty much.
I wrote a little snippet to round a number to a certain number of significant figures some time ago. You might find it useful
function sigFigs(num, figures) {
var delta = Math.pow(10, Math.ceil(Math.log(num) / Math.log(10)) - figures);
return Math.round(num / delta) * delta;
}
sigFigs(number, 3); // => 8.420e+79
Related
I have a javascript program that looks like this:
function dosine(){
var num = new Decimal(document.getElementById('num').value);
if(document.getElementById('degrad').value == "degrees"){
num = (num*Math.PI)/180;
console.log(num);
}
num = Decimal.sin(num);
console.log(num.toString());
numinverse = Decimal.asin(num);
if(document.getElementById('degrad').value == "degrees"){
num = num * (180/Math.PI);
numinverse = numinverse * (180/Math.PI);
}
document.getElementById('resultsine').innerHTML = "Sine: " + num.toString();
document.getElementById('resultinverse').innerHTML = "Inverse Sine: " + numinverse.toString();
}
In my program, I am now using Degrees.sin and Degrees.asin because of floating-point weirdness with the Math library, but when I get the sin output for 64 I get 51.49710550442818, but on my physical calculator I get 0.920026038197 0.8987940463. Am I using this library wrong, or is my code just not good? I am pretty new to javascript so advice would be very much appreciated. Thanks!
This has nothing to do with Decimal. You convert num to radians, then you take a sine of it. Finally you convert the result of the sine (which should be a proportion from 0 to 1, not an angle!) from radians to degrees, which makes no sense - it's like converting weight from feet into metres.
This could be avoided by using better naming conventions, using variable names that make sure you know what the variable contains. num is not very semantic - all it tells you is that it has a number in it. Consider angle_in_degrees, angle_in_radians and sine. Then it would be immediately obvious that this is not what you want:
angle_in_radians = Decimal.sin(angle_in_radians) // result is a sine ratio, not an angle!
angle_in_degrees = angle_in_radians * (180 / Math.PI); // good operation on bad data
Another big point is that your code does not stay in Decimal. JavaScript cannot override the default operations, so you have to use Decimal methods to calculate, not +, * and /. Note this:
Decimal(1) + 3 // incorrect
// => "13"
Decimal(1).add(3).toNumber() // correct
// => 4
Finally, unless you are dealing with financial systems, the floating point error is usually negligible; moreover, the result of sine function is irrational, so it can't be represented in Decimal any more correctly than in floating point anyway. Unless you have a use case that makes Decimal.js necessary, just use the normal numbers.
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 am trying to build a function that takes a price with 2 decimal points and finds the next highest palindrome. I know there are several other ways to approach this, but I am curious why my method is not working. I am new to JS so this might be a simple one. Any advice would be great.
I broke it into smaller chunks with explanations of what I want it to do below:
var ask = prompt("Enter a price");
var reverseIt = function (x) {
x = (parseFloat(x) * 100).toString();
for (var i = (x.length - 1); i >= 0; i--) {
x.substr(i, 1);
}
return
};
The reverseIt function takes an argument removes the decimal (* 100) and reverses the number.
var removeDec = function (j) {
return (parseFloat(j) * 100).toString();
}
The removeDec function takes an argument, removes the decimal point (* 100), and converts it back to a string. Is this redundant for comparing two "number" strings? Should I use the Number() and String() functions instead?
var findDrome = function (i) {
for (var i; removeDec(i) != reverseIt(i); i += (1 / 100)) {
if ((removeDec(i) + 1).toString() == reverseIt(i)) {
document.write(i + (1 / 100));
}
} return
};
findDrome(ask);
The findDrome function takes the ask prompt at the start as an argument. If the number without a decimal doesn't match the reverse without a decimal, then increments it by 0.01. Right before the loop ends, I wanted it to check if the number prior +1 (since it is * 100) is equal to the reverse and if so write the next number.
It wasn't working, so I tried adding parseFloat and toString to specify stricter/more explicit conversions. I also used the loose equality operators, but it's still not working.
My questions: Is this a conversion or syntactical problem or can you not compare the output of 2 functions? Should I instead compare 2 variables and if so how do I assign the for loop in the reverseIt function to a variable?
Your program has a number of issues. First, your reverseIt function never returns a reversed value. The variable x is passed in but it's never updated in the for loop - x.substr() creates a new string instance but it's never assigned back to x so its value never changes. As it is, your for loop in findDrome goes infinite since reverseIt returns undefined.
Another - possible - problem is that you're incrementing a floating-point number by 1/100 but floating point values have no exact representation. I don't know if this is actually affecting your code (since it currently never returns a proper value) but it's something you may have to worry about. This would likely affect parseFloat (which may return a slighly different floating-point value than the string it parses).
Using toFixed() would truncate the number to 2 decimal digits. You could then turn the number to a string and remove the decimal dot character, rather than converting the number back and forth between string and number.
You may want to read up on floating-point arithmetic (if you're not already familiar with it).
As a last comment, you should never, ever rely on Javascript terminating your statements - you should always use ; to terminate a statement like in other proper C-style languages. Leaving out ;-s (even if Javascript lets you get away with it) is considered very poor practice.
I figured it out thanks to the help above! Here is how the fixed program works:
var ask = prompt("Enter a price to find the next palindromic price");
var removeDec = function (j) {
return parseInt(j * 100);
};
var c = removeDec(ask);
This prompts a price and multiplies it by 100 to remove the decimal point and avoid floating point arithmetic. The parseInt removes any decimals smaller than the hundredths place.
var reverseIt = function (x) {
var a = ""
x = x.toString();
for (var i = (x.length - 1); i >= 0; i--) {
a = (a + String(x.substr(i, 1)));
}
return Number(a);
};
var b = reverseIt(c);
The reverseIt function takes an argument, converts it to string and adds each character in reverse to an empty string (a=""). Var a is then returned as a number. The empty string is important for storing the reverse number and is a big reason why my code wasn't working before.
var e = Math.pow(10, (String(c).length - 1));
Var e was added to take into account varying place values to left side of the decimal. Later this helps check if a number is equal to its reverse by adding a 1 to both sides of the number. Var e counts the length of var c (entered value with decimal removed) and finds the appropriate power of 10 to add later. So if you entered 14.40 * 100 then later it will check if 1440 + 1 is equal to 0441 + 1000.. or 10^3. This test is important later in order to exit the loop. This is where my code was failing before because I didn't take adding a number to the reverse into account and I was trying to add decimals which aren't as predictable.
if (c == b) {
document.write("$" + (c / 100) + "... This price is already palindrome!")
} else {
for (c; c !== b; c++) {
b = reverseIt(c);
if ((c + 1) == (b + e)) {
document.write("The next palindromic price is $" + ((Number(c) + 1) / 100));
break;
}
}
}
Here, If the original number and it's reverse are not equal then a loop begins that increments the value by 1 until the entered number + 1 is equal to the reversed number + e. So effectively the loop finds the number right before the loop ends, writes it and then breaks out of the loop. This palindrome finder seems to work smoothly with values big and small, no matter where you put the decimal point. Glad I got it working... it was a great learning experience figuring it out!
I can't seem to find the correct formula for having two decimal places in my code. Right now, it's rounding to three decimal places when I click on the first option in regards to calculations (not that 3 decimal places means anything. But regardless of the result, it should round to 2 decimal places). This is my last attempt:
$('#a_is_valid').one('click', function(){
if ($('#code_promo').val() == 'promocode')
{$('#gtotal').val($('#gtotal').val()-($('#gtotal').val()-
(($('#gtotal').val()*.75)))).fixed(2);
}
})
Given a number (or string representing a number), why not just do this:
var number;
var output = (Math.round(number * 100) / 100).toFixed(2);
In your case, it looks like you'd want:
$('#a_is_valid').one('click', function(){
if ($('#code_promo').val() == 'promocode')
{$('#gtotal').val((Math.round($('#gtotal').val() * 75) / 100).toFixed(2));
Math.round (appropriately enough) rounds to the nearest integer, so you'll have to do a bit of magic. Multiply by 10^(number of decimal places you want) - in your case, 10^2 or 100, round, and then divide by the same number.
In the example I made specifically for you, you'll notice I multiply by 75: 0.75 * 100.
It might be easiest to see this using a function:
function roundToNPlaces(n, val) {
var multiplier = Math.pow(10, n);
return (Math.round(val * multiplier) / multiplier).toFixed(n);
}
Then you could simply set your gtotal as follows:
$('#gtotal').val(roundToNPlaces(2, $('gtotal').val() * 0.75));
See this FIDDLE.
See:
Math.round NOTE: This documentation provides an implementation similar to (but more complex than) the code I gave. If you copy their entire Decimal rounding example in to your code (before the first time you need to use it), you can then just use Math.round10($('#gtotal').val() * .75, -2);. See http://jsfiddle.net/aW44n/1/
toFixed
For instance, I have float 1.1111111111 and need to get 11111111111 and 10.
I want to avoid functions, which may change part after point as I need it to show metric prefixes.
It may look simple with strings, I am just not sure if it is a proper way in JavaScript.
The modular division operator '%' can be used to get the remainder of a division in JS. This means that if we perform the modular division of a floating point number by 1, we get the value after the decimal point. Further, if we build a loop where we multiply by 10 until there is no longer anything after the decimal point, we can find the smallest power of ten we can multiply the original number by to get an integer.
Example below:
function getE(floatingPointValue)
{
var x = floatingPointValue;
var digitsAfterDecimal = 0;
while(x % 1 != 0)
{
x = x * 10;
digitsAfterDecimal++;
}
return x.toString() + " *10^-" + digitsAfterDecimal;
}
Fiddle: http://jsfiddle.net/L8XtP/2/
Hope this helps!