I have a some JavaScript that I use to calculate a percentage discount on a form field that holds a total value.
var thirteen = 10;
var percent_discount = (thirteen) * 0.01;
var percent_discount_final = (382.50 * (percent_discount));
console.log(percent_discount_final.toFixed(2));
The calculation is outputted at 38.24??
Why is that happening?
Well, should be the full value minus the discount - third line being:
var percent_discount_final = value_of_some_form_field - (value_of_some_form_field * percent_discount);
You almost figured out the right multiplier, but you forgot to subtract from 1, so you are multiplying by 0.1 instead of 0.9.
Here is an example of how to subtract any percentage from a number.
const subtractPercent = (value, percentage) => {
const multiplier = 1 - (percentage / 100);
return value * multiplier;
};
subtractPercent(250, 10); // 225
subtractPercent(250, 3); // 242.5
Similar to yours, this function assumes that value is positive, for simplicity's sake. Negative values will add instead of subtract.
subtractPercent(250, -10); // 275
subtractPercent(-250, 10); // -225
fun fact - float type is not precise. it came from large numbers theory, and by design it is approximation. that is why several languages provide also types like monetary etc. and for languages that don't, we calculate all monetary stuff on integers. it's not javascript related "bug", it is computer science "feature" :)
how to calculate monetary stuff on integers? well, you have to create/emulate new type. general idea is
convert all data from float to integer multiplying also by 100
perform all calculations on integers (no single float can be mixed, or the result will also be converted to float)
at the end (in most cases it's on data output / user interface) divide every value by 100
yes, in 21 century it looks plain stupid, but there is no magic you can use, when your tool (JS) doesn't have dedicated data type for monetary calculations. you have to build it.
is JS the only language involved in this project? if there is some for example some SQL db, most of them have dedicated monetary types, so you can make all your calculations on database side.
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 am stuck on how my code will not be accepted by freeCodeCamp's auto-grader. The objective was to create a function without any parameters that will generate a random number using Math.random(). Then we would have to multiply the randomly generated number by 10. After multiplying the randomly generated by 10, I would have to use Math.floor() to round it up or down.
Link to challenge: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-javascript/generate-random-whole-numbers-with-javascript
These are the objectives given to me, quoted directly from freeCodeCamp's challenge:
1.) The result of randomWholeNum should be a whole number.
2.) You should use Math.random to generate a random number.
3.) You should have multiplied the result of Math.random by 10 to make it a number that is between zero and nine.
4.) You should use Math.floor to remove the decimal part of the number.
Here is my code:
function randomWholeNum() {
var x = Math.random();
var z = x * 10;
var y = Math.floor(z);
return y;
}
As you can see, I used multiple variables to complete this task. x would generate the random number, z would store the random number multiplied by 10, y would round z, resulting in all objectives passed. However, when running the code, all objectives were ticked except for Number 3. I don't understand what went wrong, and after looking at the answer for the challenge, which is:
function randomWholeNum() {
// Only change code below this line.
return Math.floor(Math.random() * 10);
}
I don't understand why the code I wrote doesn't produce the same result of freeCodeCamp's own.
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 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
This following code for get back to vat value from percentage value and amount value using java script but its not accuracy.
var vat=((25*100)/447);
vat=vat.toFixed(1);
OK, to help, you need to specify the details you are working with. What is the VAT rate? Are you working from the gross value (includes the VAT), or the nett value (excludes the VAT).
var nVatRate = 0.2;// This is the rate of VAT in the UK at present, 20%
function VatAmountFromGross(nGrossAmount){
return nGrossAmount / (1 + (1 / nVatRate));
}
function VatAmountFromNet(nNetAmount){
return nNetAmount * (1 + nVatRate);
}
So, change the VAT rate to match yours, which I am guessing is 25% (0.25).
Using "toFixed(1)" will ensure the value is fixed to 1 decimal place - usually you need two decimal places for VAT. You will also have rounding issues if you are summing values, and these cannot be helped.
Instead of this:
var vat=((25*100)/447);
vat=vat.toFixed(1);
You should be using exact total amount:
var vat=((24.585*100)/447);
vat=vat.toFixed(3);
What you should do while saving the values in the database is round of every value to three decimal, be it vat, percentage or total amount..and to present it to the user/client you can round it off to one or two decimal places.