Javascript Money Calculations (Inconsistent Results) - javascript

I am currently trying to calculate fees that my service charges for sales (8%). The seller can input the amount they want to receive, or want's the buyer to pay (Like Steam does here: http://i.imgur.com/pLFN9px.png). I am currently using this code:
function precise_round(num, decimals) {
var t=Math.pow(10, decimals);
return (Math.round((num * t) + (decimals>0?1:0)*(Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals);
}
var elem = $(this);
elem.data('oldVal', elem.val());
elem.bind("propertychange change click keyup input paste", function(event){
if (elem.data('oldVal') != elem.val()) {
elem.data('oldVal', elem.val());
if(elem.attr("id")=="seller-gets") {
var cur = elem.val();
var value = cur*1.08;
$("#buyer-pays").val(precise_round(value), 2);
} else {
var cur = elem.val();
var value = cur*0.92;
$("#seller-gets").val(precise_round(value), 2);
}
}
});
});
The Receive(Left) <--> Pay(Right) conversions are not consistent. (Putting the same number the left produced back into the right gives a different left).
Sorry if this is not clear enough, I can explain it a little better if needed.

Those are inconsistent before you are doing two different things. Say for eg. lets take 5 as the left number.
8% of 5 = .4, So Right number will be 5.4
And if you put 5.4 as the right number 8% of it is .432 not .4. So the left number will be 5.4 - .432 = 4.968 and not 5.
If you want to get back the same number then you have to multiply by 1.08 for left -> right conversion and divide by 1.08 for the vice-versa.
Hope this helps.

Firstly, can you be sure that the values that are passed to the precise_round function are what you expect?
If not, then I think from looking at your code that you need to convert the raw values to float. I have had the same problem with values being one cent wrong, and converting to float fixed it.
var value = cur*1.08;
should be:
var value = parseFloat(cur)*1.08;
and
var value = cur*0.92;
should be:
var value = parseFloat(cur)*0.92;
After that, you can use value.toFixed(2) instead of rounding. Something to try anyway.

Related

Calculate Quantity * Price = Total | Total / Price = Quantity

I need some help.
I want the "Total" to be calculated by the "quantity * price = total" (so far it's ok). The problem is that I also need "Quantity" to be calculated by "total / price = quantity" ie if one field is changed the other will automatically change.
I made a very simple example code: JSFiddle
//Value of Price (Hidden)
$('#price').val(31245);
//Calculation
var qty=$("#qty");
qty.keyup(function(){
var total=isNaN(parseInt(qty.val()* $("#price").val())) ? 0 :(qty.val()* $("#price").val())
$("#total").val(total);
});
var total=$("#total");
total.keyup(function(){
var qty=isNaN(parseInt(total.val()/ $("#price").val())) ? 0 :(total.val()/ $("#price").val())
$("#qty").val(qty);
});
//Mask Total input
var originalVal = $.fn.val;
$.fn.val = function(value) {
if (typeof value == 'undefined') {
return originalVal.call(this);
} else {
setTimeout(function() {
this.trigger('mask.maskMoney');
}.bind(this), 100);
return originalVal.call(this, value);
}
};
$('#total').maskMoney();
$('#total').on('click mousedown mouseup focus blur keydown change input', function(event) {
console.log('This Happened:'+ event.type);
});
In it the first part "quantity * price = total" works ok and is updated automatically. However, when in the second part "total / price = quantity" is the problem appears.
When the number entered in the Total input is too large (Example: 9,876.23) the quantity is not calculated automatically and returns 0. But if the number is for example 893.23 the quantity works as it should.
Could any of you help me? (sorry for my bad english)
Ps: I needed the value of the quantity field not to exceed 8 decimals (example: 0.00000000). But in all the attempts I had the calculation does not work.
The easiest way to debug this is to breakpoint the appropriate spot and see what's happening. For instance, in Chrome, pull up your Dev Tools, find the result panel, and set a breakpoint:
Then, in the console, start evaluating parts of the expression. Here, I've evaluated total.val(). So what's happening?
The key thing to realize is that total.val() returns a string! So what happens when you use something like "9,873.76" as a number? That's right, JavaScript doesn't know what to do with the comma and punts, returning NaN.
Why did it show up when you had a number in the thousands? Because smaller numbers don't have commas.
So, as a result, you're getting zero.
The thousands separator made automatically by the mask is not understood in the calculation, so you should remove it first from the input
var qty=isNaN(parseInt(total.val().replace(",", "")/ $("#price").val())) ? 0 :(total.val().replace(",", "")/ $("#price").val())
however, the problem will appear if more than one thousands separator appears (1,000,000), so you you can globally remove all thousands separators:
var my_total = total.val().replace(/,/, "");

How to simulate the result of a Google Sheet multiplication formula in Javascript?

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

JavaScript - Moving decimal place to the right

I'm trying to get the decimal place to move to the right and give me at least a 2 digit whole number. I've got the places after the decimal figured out, but not before the decimal.
The input value is divided by 36 and it's supposed to result in a percentage.
There's a fiddle here...
$(function() {
var output_element = $('#creditRemaining');
$('#creditRemaining').keyup(function() {
updateTotal();
});
var updateTotal = function () {
var input1 = parseInt($('#creditRemaining').val() || 0);
$('#total').text((input1 / 36).toFixed(2) + "% Prorated");
};
});
Thoughts?
Multiply it by 100 and then use .toFixed(2)
Then this line looks like this:
$('#total').text(((input1 / 36)*100).toFixed(2) + "% Prorated");

Rounding the number within two digits after the comma with javascript

I have a product to add into the store, where there are two input fields priceBase and priceFinal. First is without TAX, second is with TAX.
While using this javascript function:
jQuery(function($){
var priceBase = $('input[name="mprices[basePrice][]"]', '#productPriceBody');
var priceFinal = $('input[name="mprices[salesPrice][]"]', '#productPriceBody');
var priceDiff = priceFinal.val() - priceBase.val();
var priceTax = priceDiff / priceBase.val();
alert(priceFinal.val()); // 1.40004
alert(priceBase.val()); // 1.16667
alert(priceDiff); // 0.23333399999999993
alert(priceTax); // 0.19999999999999993
});
How I suppose to round a priceTax value from 0.19999999999999993 to 0.20 ? Like normal math calculation you know, if it's 4 and below, it rounds to lower, if it's 5 it rounds to higher number.
Thanks for suggestions in advance.
You seem to want
alert(priceDiff.toFixed(2));
But you should parse the values before you do maths. It works here because you're lucky :
"33"-"12" => "21"
"33"+"12" => "3312"
So to avoid bugs in the future (when you use + instead of - for example) I'd suggest to always parse the field values :
var priceDiff = parseFloat(priceFinal.val()) - parseFloat(priceBase.val());

multiplying values

Im using the following method to add up text boxes. I have tried changing multiple things and cant seem to multiply two text box values! essential I want 2 text box that values are multiplied and displayed in a third text box. I want this value to be fluid aka change when the number changes! I was using this code because i may be multiplying more then one thing but if this is too much of a hassle i will live with just multiplying two at a time
The code im using to add is
<!--adding script #-->
<script>
$(document).ready(function(){
calculateSum();
//iterate through each textboxes and add keyup
//handler to trigger sum event
$(".txt").each(function() {
$(this).keyup(function(){
calculateSum();
});
});
});
function calculateSum() {
var sum = 0;
$("#sum").val(sum.toFixed(2));
//iterate through each textboxes and add the values
$(".txt").each(function() {
//add only if the value is number
if(!isNaN(this.value) && this.value.length!=0) {
sum += parseFloat(this.value);
}
});
//.toFixed() method will roundoff the final sum to 2 decimal places
$("#sum").html(sum.toFixed(2));
var total = document.getElementById("subtotal").value == "";
var total = document.getElementById("subtotal").value = sum;
}
<!--END adding script #-->
I tried setting the last line to
var times1 = document.getElementById(subtotal);
var times2 = document.getElementById(tax);
var equal = times1.value * times2.value;
and then changing var total1 = document.getElementById("total1").value = sum9; to var total1 = document.getElementById("total1").value = equal;
The text boxes id are subtotal and tax the box im trying to update is total1.
Thanks alot!
On every keyup, instead of getting all values and adding them explicitly, it is better to deduct the previous value of the corresponding input and add the current updated value to sum..
Also, if subtotal is correctly calculated, then the multipication operation what ever you have done should work correctly..
Please find the following jsfiddle where the sum is calculated as explained above along with multiplying the tax..
http://jsfiddle.net/tgvrs_santhosh/77uxK/1/
Let me know if you still face the issue..
Instead of this
if(!isNaN(this.value) && this.value.length!=0) {
I think a regular expression may work better because you are using string values
if (/^([-]?((\d+)|(\d+\.\d+)|(\.\d+)))$/.test(this.value)) {
I haven't tested this regex, but you should be able to find a good regex to test for valid numbers if this one doesn't work for some reason. Also I noticed you have a == after that getElementById.
I'm not totally certain it matters, but you can do sum += (this.value * 1) instead of parseFloat.
update
Try this var equal = ($("#subtotal").val() * 1) * ($("#tax").val() * 1);
I found your question very confusing, but I think what you're trying to say is you want to add up all the .txt fields to get a sub-total, then multiply that sub-total by a tax rate to get a total. If so, then you already know the sub-total is a valid number due to the way you calculate it, so then:
var tax = +$("#tax").val(), // get tax and convert to a number
total = tax ? sum * tax : sum; // if tax is a non-zero number multiply
// otherwise just take the sum as is
If your tax field is not an input then use .text() instead of .val().
Your existing code is rather more complicated than it needs to be. You can do this:
$(document).ready(function(){
calculateSum();
// you don't need an .each() loop, you can bind a keyup handler
// to all elements in the jQuery object in one step, and you don't
// need the anonymous function since it does nothing but call calculateSum:
$(".txt").keyup(calculateSum);
});
function calculateSum() {
var sum = 0,
val;
//iterate through each textboxes and add the values
$(".txt").each(function() {
// you don't need to test for NaN: just attempt to convert this.value
// to a number with the unary plus operator and if the result is not
// a number the expression val = +this.value will be falsy
if(val = +this.value)
sum += val;
});
$("#sum").html(sum.toFixed(2));
var tax = +$("#tax").val();
$("#total1").html((tax ? sum * tax : sum).toFixed(2));
}
For some reason the unary plus operator used throughout my answer is not widely known, but I prefer it to parseFloat().

Categories