These forums are now Read Only. If you have an Acrobat question, ask questions and get help from one of our experts.

Rounding or truncating a Javascript calculation

steveald
Registered: Jun 29 2010
Posts: 15
Answered

I have a calculation entered as Simplified Field Notation for a field on an interactive pdf where a user can enter values and the form auto-calculates other fields based on what is entered.
 
Simplified, the calculation is a*(100-b)/100. Given a=0.54 and b=15, the field yields 0.459 which is shown to 2 decimal places on the pdf as 0.46.
 
I need to round that answer to 2 decimal places so that another calculation pulls 0.46 from this field instead of 0.459. In Excel or elsewhere, I would round 0.459 to 2 decimal places. Or I would multiply 0.459 times 100, truncate the decimal, then divide by 100. Either way, the next calculation needs to think the calculated value in that field is 0.46, not 0.459.
 
Is there a javascript command I can add to the calculation to achieve this? If it helps any, the other calculation is set up as "Value is the product (x) of the following fields:" with the above field listed as one of the factors (which I would guess limits where something can be done).
 
Thank you.

My Product Information:
Acrobat Pro 8.1.6, Macintosh
gkaiseril
Expert
Registered: Feb 23 2006
Posts: 4307
The "simplified field calculations" is very limited as to what field names can be used and there is no way to use a field's properties or methods or call a function, so you will need to use a more complex JavaScript to perform the rounding.

JavaScript has a 'round' method for the 'Math' object, but this does not always round correctly due to the way in which floating point numbers are stored and computed by the computer.

Also it is not a good idea to perform a division in the 'simplified field notation' calculation unless you know that under all circumstances you know that the divisor will not be zero or null.The rounding function can be performed by use of either the 'Math.round()' or 'util.printf()' methods.

Using the 'Math.round()' method one could write the following funciton:

function Round(fNumber, fDec) {
/*
Purpose: Round a number to a given number of decimal places

Parameters:
fNumber - number to be rounded
fDec - number of decimal places to round to.
If omitted zero decimal places is assumed.
Function will work just like Math.round method

Returns number rounded to given number of decimal places
*/

// check to see fDec passed
if(typeof fDec == 'undefined') {
// fDec parameter does not exist
fDec = 0; // force value to zero
}
fDec = Math.floor(fDec); // only allow whole numbers
// compute value for decimal adjustment
var fAdjust = Math.pow(10, fDec);
// compute and return rounded number
return Math.round(fNumber * fAdjust) / fAdjust;
} // end of Round funciton

Using the 'util.printf()' method, which does not appear to have a problem, one can use the following funciton;

function Round(nValue, nDec)
{
return Math.round(Number(nValue) * Math.pow(10, Number(nDec))) / Math.pow(10, Number(nDec));
// return Number(util.printffunctionnumber( "%,0 ." + Numbeadjustr(nDec)functionfunction + "f", Number(nValue))) ;
}

Using a function to perform the rounding will allow one to reuse the code in more than one calculation or other JavaScript application.

If you want to use a calculation option other then the 'custom JavaScript' you can use the 'custom javascript' on the 'Validation' tab to perform the rounding.

if (event.valueAsString != "") event.value = Round(event.value,2);

If you want to use the 'custom JavaScript calculation' with the Round function:

var a = Number(this.getField('a').value);
var b = Number(this.getField('b').value);




event.value = Round( (a * (100 - b) / 100), 2);

If you do not want to use the Round function:

// get variables as number
var a = Number(this.getField('a').value);
var b = Number(this.getField('b').value);
// compute
var nValue = a * (100 - b) / 100;
// format for 2 decimals
var cRound = "%,0 ." + 2 + "f";
// round the computed value
event.value = util.printf( cRound, nValue);




George Kaiser

try67
Expert
Registered: Oct 30 2008
Posts: 2398
JavaScript has several such functions:
- Math.floor()
- Math.ceil()
- Math.round()
You can read about them here: http://www.w3schools.com/jsref/jsref_obj_math.asp

But if you use any of those methods, then you can't use the Simplified Notation field anymore. You will have to write a custom calculation script in JavaScript.

- AcrobatUsers Community Expert - Contact me personally at try6767 [at] gmail [dot] com
Check out my custom-made scripts website: http://try67.blogspot.com

steveald
Registered: Jun 29 2010
Posts: 15
Thanks everyone. I think my head just grew a size or two. I'll be sure to check out that link, try67.

George, it sounds like the simplest method may be this?

1. On the Calculate tab, leave the formula as entered in the "Simplified field notation" field. (Of course, "a" and "b" are actually valid field names.)

2. On the Validate tab, select "Run custom validation script" and enter the following in the field:

if (event.valueAsString != "") event.value = Round(event.value,2);

Is that about right?

Thanks again.
George_Johnson
Online
Expert
Registered: Jul 6 2008
Posts: 1876
steveald wrote:
if (event.valueAsString != "") event.value = Round(event.value,2);

There is no valueAsString event property. The type of event.value will always be string. So this can be changed to simply:

if (event.value) event.value = Round(+event.value, 2);


gkaiseril
Expert
Registered: Feb 23 2006
Posts: 4307
A quick check of the Acrobat JS API Referecne:

valueAsString

Returns the value of a field as a JavaScript string.
It differs from value, which attempts to convert the contents of a field contents to an accepted format. For example, for a field with a value of “020”, value returns the integer 20, while valueAsString returns the string “020”.

George Kaiser

steveald
Registered: Jun 29 2010
Posts: 15
If I use either version of the 'custom javascript' on the 'Validation' tab and show the field out to 4 decimal places, neither version results in a 2-place decimal (or 0.46 in my example).

If I try to use the 'custom JavaScript calculation' with the Round function option as I see it written (substituting "a" and "b" for the necessary field names) nothing appears in the field. I must be missing something.

Further, this has become very frustrating in that fields change their values when data is entered in other fields that have nothing to do with the calculation in the changing field - and they appear to be changing randomly at that.

If I may, here is what I am doing:
1. A field called "CurrentLifeADDRate" takes input from the user - invariably a 2-place decimal value less than 1 (such as 0.54).
2. Another field called "YearsWithCarrier" takes input as a single digit, usually less than 10 (such as 5).
3. A field called "ApplicableDiscount" yields one of three values (in this case, 15) based on "YearsWithCarrier" using the following formula (obtained on this site):

YearsWithCarrier = this.getField("YearsWithCarrier").value;
if (YearsWithCarrier<3) {
event.value = "10";
} else if (YearsWithCarrier>4) {
event.value = "15";
} else event.value = "12.5";

4. A field called "DiscountedLifeADDRate" uses the following formula (which I simplified using "a" and "b" earlier) to calculate a new value which is the entry in step 1 reduced by the result in step 3 as a percentage. (In this case, 0.54 reduced by 15% is 0.459 which needs to be rounded to 0.46 for another calculation:

CurrentLifeADDRate*(100-ApplicableDiscount)/100

5. A field called "TotalVolumeofLifeInsurance" takes input from the user, usually a whole number greater than 100,000 or even 1,000,000.
6. A field called "DiscountedMonthlyPremium" is calculated as Value is the product of "TotalVolumeofLifeInsurance", "DiscountedLifeADDRate", and "1000thPlace" (which is just a hidden field containing the value .001). This result varies greatly when "DiscountedLifeADDRate" is 0.459 or 0.46. That's what I need to fix here.
7. A field called "CurrentSTDMonthlyPremium: takes input from the user as a number out to 2 decimal places.
8. The last field, called "NewTotalMonthlyPremium" is calculated as Value is the sum of the amounts in steps 6 and 7.

Here's where it gets frustrating. If I enter 0.54 in the step 1 field, 0.486 appears for step 4 since the field for step 2 is still empty making the step 3 value 10 (0.54 reduced by 10% = 0.486). If I enter 5 for step 2, the step 3 amount changes to 15, but the step 4 amount doesn't change. If I enter a value for step 5, then the step 4 amount changes to the correct value (except it's still not rounded to 2 places like I need it to be). BUT, the value in step 6 is wrong - it uses the original value from step 3, not the current one. If I enter a value in the step 7 field, THEN the step 6 value corrects itself. BUT, then the value in step 8 is wrong - it uses the original value from step 3 as well. It only corrects itself after I enter something in another field that has nothing to do with the calculations.
The other frustrating aspect occurs when I start changing values. It looks like I have to re-enter the same value two or three times to get all the calculations to catch up to the current entries in all fields. Is there any help for this behavior?
George_Johnson
Online
Expert
Registered: Jul 6 2008
Posts: 1876
gkaiseril wrote:
A quick check of the Acrobat JS API Referecne:
Right, but that's a property of a field object, not a property of the event object. "event.valueAsString" returns "undefined". "event.value" will always be a string.

gkaiseril
Expert
Registered: Feb 23 2006
Posts: 4307
I do not have that problem with version 5, 6, 7, or 8.

George Kaiser

steveald
Registered: Jun 29 2010
Posts: 15
At any rate, neither one of them worked - as stated above.
George_Johnson
Online
Expert
Registered: Jul 6 2008
Posts: 1876
If you place the following in the Validate event of a text field:

app.alert(event.valueAsString);

does it show something other than "undefined" when the field value changes? If so, what?
George_Johnson
Online
Expert
Registered: Jul 6 2008
Posts: 1876
steveald wrote:
The other frustrating aspect occurs when I start changing values. It looks like I have to re-enter the same value two or three times to get all the calculations to catch up to the current entries in all fields. Is there any help for this behavior?
You should make sure that the field calculation order is set to something that makes sense for your form.

steveald
Registered: Jun 29 2010
Posts: 15
George_Johnson wrote:
If you place the following in the Validate event of a text field:app.alert(event.valueAsString);

does it show something other than "undefined" when the field value changes? If so, what?
No. I did as you said and a window popped up saying "undefined".
steveald
Registered: Jun 29 2010
Posts: 15
George_Johnson wrote:
You should make sure that the field calculation order is set to something that makes sense for your form.
How is that done? Tabbing between fields progresses in the right order.

Is there some way to tell all calculations to constantly update?
George_Johnson
Online
Expert
Registered: Jul 6 2008
Posts: 1876
In form editing mode, select "Forms > Edit Fields > Set Field Calculation Order", at least in Acrobat 9. Something similar in previous versions.The Calculate event is triggered for a field whenever any other field value changes, according to the order you set with the field calculation order, which is different than the tab order.
steveald
Registered: Jun 29 2010
Posts: 15
Once I put it in form editing mode, that worked exactly as described. Everything calculates perfectly now. Thank you.


Now I'm back to where I started with the rounding.

Under the Calculate tab, I have for Simplified field notation: CurrentLifeADDRate*(100-ApplicableDiscount)/100

Under the Validate tab, I have for Run custom validation script: if (event.valueAsString != "") event.value = Round(event.value,2);

To check my results I set the field to show out to 4 decimal places. Unfortunately, 0.54 reduced by 15% is still showing up as 0.4590, not 0.4600 as it needs to be. (It needs to calculate exactly as it will appear when the field is set to show out to 2 decimal places.)
George_Johnson
Online
Expert
Registered: Jul 6 2008
Posts: 1876
Try the following for the Validate script:

event.value = util.printf("%.2f", +event.value);
steveald
Registered: Jun 29 2010
Posts: 15
Jackpot!

Thank you.
gkaiseril
Expert
Registered: Feb 23 2006
Posts: 4307
Here is a working example Rounding with Printf for both the simplified field and custom calculation.https://acrobat.com/#d=XAFTyOAAMf2fnrBOHs6cGg

George Kaiser

steveald
Registered: Jun 29 2010
Posts: 15
Thanks, but the link doesn't appear to work. You got me exactly what I need though.