Formatting numbers in a form function

B

Buzby

Probably a very basic question but I'm completely stuck.

I have a simple function that takes a quantity and a price and
multiplies it.

function
Item1(f){f['TP1'].value=Number(f['Quant1'].value)*Number(f['Price1'].val
ue);

Quant1 is taken from a text form field and Price1 from a hidden form
field.

When Quant1 is changed by calling function Item1
onchange="Item1(this.form);" the calculated price is displayed in form
field TP1.

This works perfectly - but occasionally it displays an odd number

ie: 5 x 4.97 = 24.849999999999998

Any pointers as to how I get it to format to 2 decimal places - I've
tried all sorts but to no avail

TIA!
 
S

SAM

Le 4/28/09 4:19 PM, Buzby a écrit :
Thanks - can't wsee that one working for me - I was hoping for a
toFixed(2) kins of solution!

If only an approximation is enough for you

function decim(n) {
n = (Math.round(n*100)/100) + '';
if(n.indexOf('.')<0) n = n + '.00';
else
while(n.substring(n.indexOf('.')).length<3) n = n+'0';
return n;
}

alert('tests :\n5 x 4.97 = ' + decim(5*4.97) +
'\n2 x 0.7 = ' + decim(2*.07) );

f.result.value = decim(f.num1.value * f.mum2.value);
 
M

Matthias Reuter

Buzby said:
I have a simple function that takes a quantity and a price and
multiplies it. [snip]
This works perfectly - but occasionally it displays an odd number
ie: 5 x 4.97 = 24.849999999999998

To avoid floating point problems you could define the price in cents
instead of dollars (replace cent/dollar by a currency of your choice).
Thus you only have to calculate "integers" which are precise, at least in
a reasonable range.

function calculatePrice (f) {
var priceInCent = parseInt(f.Price1.value, 10);
var quantity = parseInt(f.Quant1.value, 10);

var total = priceInCent * quantity;

f.TP1.value = Math.floor(total / 100) + "." + (total % 100);
}

Matt
 
S

SAM

Le 4/29/09 10:31 AM, Matthias Reuter a écrit :
To avoid floating point problems you could define the price in cents
instead of dollars (replace cent/dollar by a currency of your choice).
Thus you only have to calculate "integers" which are precise, at least
in a reasonable range.

function calculatePrice (f) {
var priceInCent = parseInt(f.Price1.value, 10);
var quantity = parseInt(f.Quant1.value, 10);

var total = priceInCent * quantity;

f.TP1.value = Math.floor(total / 100) + "." + (total % 100);
}

Did you really test your function ?

(P1 * 100) * (P2 *100) = (P1 * P2) * 10000 !!!!!!

and trying to correct it :

var total = parseInt(priceInCent * quantity / 100, 10)

gives 2.92 instead of 2.93
for : 0.07 * 41.80 = 2.926 --> 7 * 4180 = 2.92

My decim function doesn't make this error
 
M

Matthias Reuter

SAM said:
Did you really test your function ?

(P1 * 100) * (P2 *100) = (P1 * P2) * 10000 !!!!!!

and trying to correct it :

var total = parseInt(priceInCent * quantity / 100, 10)

gives 2.92 instead of 2.93
for : 0.07 * 41.80 = 2.926 --> 7 * 4180 = 2.92

My decim function doesn't make this error

I have the feeling you misunderstood my function. Both priceInCent and
quantity are integers. Thus total (maybe better labelled as totalInCent)
is an integer as well.

If you need non-integer quantities my function won't work.

Matt
 
S

SAM

Le 4/29/09 12:02 PM, Matthias Reuter a écrit :
I have the feeling you misunderstood my function. Both priceInCent and
quantity are integers. Thus total (maybe better labelled as totalInCent)
is an integer as well.

and we get : 292.60
and what was asked was : 2.93 (2 numbers after the separator)

rounding the final/non-integer/price could also give curious numbers as
2.92599999992
I presume ?

If you need non-integer quantities my function won't work.

OK

but it doesn't give a number with 2 decimals
as wanted : <[email protected]>
 
M

Matthias Reuter

SAM said:
Le 4/29/09 12:02 PM, Matthias Reuter a écrit :

and we get : 292.60
and what was asked was : 2.93 (2 numbers after the separator)

rounding the final/non-integer/price could also give curious numbers as
2.92599999992
I presume ?



OK

but it doesn't give a number with 2 decimals
as wanted : <[email protected]>

Yes it does. Let me modify my function to get rid of the form, so anyone
can test it in a console:

function calculatePrice (priceInCent, quantity) {
priceInCent = parseInt(priceInCent, 10);
quantity = parseInt(quantity, 10);

var totalInCent = priceInCent * quantity;

return Math.floor(totalInCent / 100) + "." + (totalInCent % 100);
}

Now the example in the OP was quantity 5, price 4.97, that is priceInCent
497.

calculatePrice("497", "5")
-> 24.85

Which is the correct answer.

Matt
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected].
fr>, Tue, 28 Apr 2009 22:04:55, SAM <[email protected].
invalid> posted:
If only an approximation is enough for you

function decim(n) {
n = (Math.round(n*100)/100) + '';
if(n.indexOf('.')<0) n = n + '.00';
else
while(n.substring(n.indexOf('.')).length<3) n = n+'0';
return n;
}

Try Infinity - evidently Infinity is an integer <G>.

You calculate n.indexOf('.') twice.

Note that the while loop can execute at most once.

The code simplifies to

function decim(n) {
n = (Math.round(n*100)/100) + '';
var K = n.indexOf('.')
if (K<0) n += '.00'
if (n.length==K+2) n += '0'
return n; }


It can be made shorter and wider as

function decim(n) { return ((Math.round(n*100)/100) + '').replace(/^(-?\d+)$/, "$1.00").replace(/(\.\d)$/, "$10") }

which has the defect that null and undefined are misrepresented as NaN.
It could serve as a demonstration of simple RegExp usage.

Both added to js-rndg2.htm.

Unless there is a guarantee that such routines will be used only with
smallish numerical inputs, they should be tested with large numbers,
Infinity, -Infinity, null, NaN, undefined, and anything else that might
possibly be provided. They should *never* give a numerically-misleading
result, and should *always* give a benign one.
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]>,
Math.floor(totalInCent / 100) + "." + (totalInCent % 100);

totalInCent = 1234, result = 12.34 OK.
totalInCent = 1204, result = 12.4 Ha Ha Ha.

Also :
quantity = parseInt(quantity, 10); // Works
quantity = +quantity // Works better
 
B

Buzby

SAM said:
Le 4/28/09 4:19 PM, Buzby a écrit :

If only an approximation is enough for you

function decim(n) {
n = (Math.round(n*100)/100) + '';
if(n.indexOf('.')<0) n = n + '.00';
else
while(n.substring(n.indexOf('.')).length<3) n = n+'0';
return n;
}

alert('tests :\n5 x 4.97 = ' + decim(5*4.97) +
'\n2 x 0.7 = ' + decim(2*.07) );

f.result.value = decim(f.num1.value * f.mum2.value);

I changed

f['TP1'].value=Number(f['Quant1'].value)*Number(f['Price1'].value);

to

f['TP1'].value=(Number(f['Quant1'].value)*Number(f['Price1'].value)).toF
ixed(2);

Job done

Thanks for the pointers though - bookmarked!
 
T

Thomas 'PointedEars' Lahn

Dr said:
totalInCent = 1234, result = 12.34 OK.
totalInCent = 1204, result = 12.4 Ha Ha Ha.

Fix:

Math.floor(totalInCent / 100) + "." + leadingZero(totalInCent % 100, 2);
Also :
quantity = parseInt(quantity, 10); // Works
quantity = +quantity // Works better

The latter certainly works faster -- but *better*? +"0x71" as conversion
of a a non-decimal input results in 113; how is that better than
parseInt("0x71", 10) which results in 0 following in the reasonable
assumption the user simply mistyped?


PointedEars
 
D

Dr J R Stockton

In comp.lang.javascript message said:
I changed

f['TP1'].value=Number(f['Quant1'].value)*Number(f['Price1'].value);

to

f['TP1'].value=(Number(f['Quant1'].value)*Number(f['Price1'].value)).toF
ixed(2);

Job done

Provided that none of your users are running Internet Explorer and get a
product value for which IE shows an incorrect answer. The error cases
that I know about should not trouble a billing application; but there
could be others.

To convert string to number, unary + is faster to type and faster to run
than Number(); but using multiplication will make the conversion
automatic.
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]>, Thu, 30
Apr 2009 01:03:30 said:
Fix:

Math.floor(totalInCent / 100) + "." + leadingZero(totalInCent % 100, 2);

One should assume that, on seeing the problem. MR would have seen the
solution.
The latter certainly works faster -- but *better*? +"0x71" as conversion
of a a non-decimal input results in 113; how is that better than
parseInt("0x71", 10) which results in 0 following in the reasonable
assumption the user simply mistyped?

On my, and I expect most, keyboards, the letter x is nowhere near any of
the digits; moreover, when typing a non-zero integer, very few people
will start by typing zero. The most probable interpretation of 0x71 is
that the user had some reason for using Hex.

You could have been smarter and suggested 1e5 as a typo for 135 or 145;
or 8j as a typo for 81 (using laptop embedded numerics with Num Lock
off, US/UK layout).


In any case, there's generally no point in bothering about alphabetics
in a number unless one also bothers about incorrect digits in a number;
the only sensible alternatives are to believe whatever is first keyed
in, or to verify the numbers independently of the original input.
Nothing in between makes real sense.

One can write, for input element ID,
var idv = ID.value = +ID.value
then work with idv, and require the user to check the inputs visually
before committing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top