Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Input Mask Behaviour

Status
Not open for further replies.

cibe86

Programmer
Sep 12, 2013
12
IT
Hi,
I have a text field with an input mask like this ###,###,###.## and I can't understand the behaviour in rounding values in this case.
If the value of the field is, for example, 10.129899 then it shows 10.12 but if the value is 10.129999 it shows 10.13.
So, in which case VFP rounds values?

I would like that the input mask always rounds values. I need rounding only in visualization, keeping the value of the control with all his decimal pieces for further calculation.
The behaviour doesn't change if the input mask is 999,999,999.99

Thank you!!
 
The InputMask property does not directly affect rounding. It only determines what characters you allow to be entered in the input field.

If you want full control over rounding, use the ROUND() function.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thank you Mike for the response.
So why when you programmatically set the value 10.129999 it shows 10.13 ?
I can't use the ROUND() because the control is buonded to a cursor and in the cursor I need all the decimal digits.
Thank you
 
I just checked Transform, and it disaplays 10.13 in both cases to me with default settings

? Transform(10.129899,"@R ###,###,###.##")
? Transform(10.129999,"@R ###,###,###.##")

If you SET DECIMALS 18 for example, the display is buggy, it rounds 0.129999 but not 0.129899

So the suggestion of mike remains, you should use round, you don't have to change the field value, you can set controlsource="(round(field,2))".

Bye, Olaf.

 
Hi,
You may want to check your settings for DECIMALS and FIXED and how they affect the field type (please read below from Hacker's Guide to Visual FoxyPro 7 by Tamer E. Granor and Ted Roche)
These two commands determine display and calculation of numbers involving decimals. SET DECIMALS determines the minimum number of decimals used and displayed. SET FIXED determines whether the SET DECIMALS value is also the maximum number displayed.

Usage
SET DECIMALS TO [ nDecimals ]
SET FIXED ON | OFF
nDecimalSetting = SET( "DECIMALS" )
cIsItFixed = SET( "FIXED" )

When you perform a calculation involving decimal numbers, SET DECIMALS sort of determines the number of decimal places in the result. To be more specific, it determines the number of decimal places you'll see in the result, if the result has more places than the current setting. The correct calculation is performed and stored internally, but all subsequent displays of the result use the DECIMALS setting at the time the number was calculated. (If the result has fewer places than the DECIMALS setting and FIXED is OFF, the result is not padded with zeroes.)

If that sounds confusing, it's because it is. Try this:

X1 = 10/3 && with default DECIMALS setting of 2
? X1 && 3.33, as expected
SET DECIMALS TO 5
X2 = 10/3
? X2 && 3.33333 - so far, so good
DISPLAY MEMORY LIKE X*
Interesting—X1 shows up as 3.33 while X2 is 3.33333. But it gets stranger.

? X1*2 && 6.67
? X2*2 && 6.66667
SET DECIMALS TO 18
? X1*2 && 6.67
? X2*2 && 6.66667
? X1*3 && 10.00
? X2*3 && 10.00000 - so no precision was lost in either case
The variables remember how many decimal places they were created with, even though you can see in the memory listing that the internal representations are the same.

What does all this mean for you? That you should choose a decimals setting for your application and use it throughout.


SET DECIMALS TO without a number resets you to the default of 2, even if you've set a different default through the Tools | Options dialog.


SET FIXED is much easier. When you turn it on, every number is displayed with the DECIMALS setting, even if the actual result is shorter or longer. That is, it rounds or pads numbers to exactly the specified number of decimal places.

SET DECIMALS affects Currency and Integer values only when SET FIXED is ON. In that case, Integer values are shown with the number of decimal places indicated by SET("DECIMALS"). Currency is more interesting—the number of decimal places shown can be decreased if SET("DECIMALS") is less than four, but it never goes above four.

Both FIXED and DECIMALS are scoped to data sessions.

Example
* Using X1 and X2 created above
SET DECIMALS TO 3
SET FIXED ON
? X1 && 3.333
? X2 && 3.333
? X1*2 && 6.667
yMoney = $37.5837
? yMoney && 37.584
SET DECIMALS TO 7
? yMoney && 37.5837
hth

MK
 
Interesting behavior.

Code:
PUBLIC ofrm
ofrm=CREATEOBJECT("MyForm")
oFrm.show()

DEFINE CLASS myform as form
	ADD object txt as textbox with value=10.1119994999,inputmask="###,###,###.###"
	ADD object txt2 as textbox with value=10.1119995,inputmask="###,###,###.###",left=150
	ADD object txt3 as textbox with value=10.129994999,inputmask="###.##",top=30
	ADD object txt4 as textbox with value=10.129995,inputmask="###.##",top=30,left=150
	ADD object txt5 as textbox with value=10.9994999,inputmask="###",top=60
	ADD object txt6 as textbox with value=10.9995,inputmask="###",left=150,top=60
	ADD object txt7 as textbox with value=101.99899999,inputmask="#,###",top=90
	ADD object txt8 as textbox with value=101.999,inputmask="#,###",left=150,top=90
	ADD object txt9 as textbox with value=1100.99899999,inputmask="#####",top=120
	ADD object txt10 as textbox with value=1100.999,inputmask="#####",left=150,top=120
ENDDEFINE

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
Just the usual rare case of conversion "errors" inherent in floating point arithmetic.

You have a round trip of conversions here. Your source code decimal values are put into double floating point memory variables and then converted back to strings. I can't even tell you what VFP does first, taking into account the input mask or converting the numeric value to a string.

Anyway, no matter how much you would insist there is a certain precision guaranteed, the nuance of a tid bit can decide whether some rounding operation works as expected or not, even at just the third or second decimal place. The more so, as I don't see the input mask should simply cut off or round numbers.

Anyway, I would always take an approach of first rounding, then converting, to have more control about the process. I have some delicate experience about sums of values needing to result in 100%.

See
Bye, Olaf.
 
You're right, but I was curios. I believe it's a little more complicated. I saw some patterns.

1 It depends on picture mask
If inputmask has n decimals, then if I added three more 9 (decimal at the position n+1 is 9, decimal at the position n+2 is 9 and decimal at the position n+3 is 9) then the strange effects appears.
Examples:
a) inputmask="######.#" (one decimal)
To intercept, I displayed a number with one decimal followed by three 9 and something else.
[pre]number displayed
0.09994999999 0.0
0.09995 0.1
0.09990 0.0
0.0999 0.1[/pre]
(The last two are the most weirdest)
If I cut one of the nine's in any of the fourth from the above, the result is displayed as 0.0
[pre]0.0994999999 0.0
0.0995 0.0
0.0990 0.0
0.099 0.0[/pre]
If I add one more nine in any of the fourth from the above, the result is displayed as 0.1
Now I increased the number of decimals in the input mask, exactly the same behavior occurs but one decimal to the right
b) inputmask="######.##" (two decimals)
To intercept, I displayed a number with two decimal followed by three 9 and something else.
[pre]number displayed
0.009994999999 0.00
0.009995 0.01
0.009990 0.00
0.00999 0.01[/pre]
If I cut one of the nine's in any of the fourth from the above and the result is displayed as 0.00
[pre]0.00994999999 0.00
0.00995 0.00
0.00990 0.00
0.0099 0.00[/pre]
I've tested also with 3 and four decimals and I saw the same behavior.
The same behavior when inputmask contains no decimals:
To intercept, I displayed an integer number followed by three 9 and something else after the decimal point.
c) inputmask="#######" (no decimals)
[pre]number displayed
0.9994999 0
0.9995 1
0.9990 0
0.999 1[/pre]

2. Also depends on the internal representation, because there are some thresholds on particular powers of 2.
For two decimals, the threshold is 128 (2^7), for three or four decimals the threshold is 64 (2^6)
a) inputmask="######.##" (two decimals)
[pre]number displayed
127.009994999999 127.00
127.009995 127.01
127.009990 127.00
127.00999 127.01[/pre]
while
[pre]128.009994999999 128.00
128.009995 128.01
128.009990 128.00
128.00999 128.00[/pre] (patterns changes)
The same thing for integers
b) inputmask="#######" (no decimals)
[pre]number displayed
127.9994999 127
127.9995 128
127.9990 127
127.999 128[/pre]
but
[pre]128.9994999 128
128.9995 129
128.9990 128
128.999 128[/pre]
(i detected another threshold at 2^14 and 2^15)

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
See
Christof Wollenhaupt said:
But what is a variable in Visual FoxPro? Variables in FoxPro can store values of any data type. However, as Visual FoxPro is written in C itself, FoxPro variables, as well, have to be stored in a C format at some point. Visual FoxPro stores variables in a C structure. Even though the following structure comes from the Library Construction Kit, it's probably close to what Visual FoxPro uses internally, if not even identical:

typedef struct {
char ev_type;
char ev_padding;
short ev_width;
unsigned ev_length;
long ev_long;
double ev_real;
CCY ev_currency;
MHandle ev_handle;
unsigned long ev_object;
} Value;
In addition to the type, there's an entry for each supported data type. Visual FoxPro uses different fields depending on which data type should be stored. The structure explains why strings can contain any characters (because their length is stored separately) and [highlight #CC0000]how Visual FoxPro deals with the number of decimal places in floating point values to allow for differences between 1.0 and 1.00[/highlight]. The actual string and objects are not stored directly in this structure as their size can vary widely. To access strings, Visual FoxPro uses a so called memory handle which will be explained in just a moment. Objects are identified using a not closer documented 32-bit number. It might surprise that arrays are not mentioned at all.

So it's all about the internal representation of the decimal numbers, which is more than a simple float, it also stores the precision of the float and makes a difference between 128.999 and 128.9990, too, for example.

Unless you decompile the VFP runtime you'll never deduct what really happens behind the scenes, you can shorten it and blame the input mask. It plays a role for sure, as float arithmetics won't explain a difference between same numbers, that would result in the same float otherwise.

Bye, Olaf.
 
Sorry, I should have previewed that, I meant to change the text color, not the back color. The highlighted sentence above is:

Christof Wollenhaupt said:
[highlight #FCE94F]how Visual FoxPro deals with the number of decimal places in floating point values to allow for differences between 1.0 and 1.00[/highlight]

Bye, Olaf.
 
I agree with all you said. I also read a part of the extensive documentation from the link you gave. Thanks for that.
It was just a weekend fun for me to do this small analyze [smile].
I only said that it's a pattern who depends on the number of decimals of the Input mask.
The interesting behavior occurs every time when the numbers had 3 additional decimals (three nines, 999) to the length of the picture mask (exactly 3 nines, no less).
If picture mask is ### (no decimals), then n.999
If picture mask is ###.# (one decimal), then n.i999
If picture mask is ###.## (two decimals), then n.ij999
and so on.
Maybe in this case the picture mask and not the number itself tells VFP the precision.
For me it's new (and useful) to find that the value (not the result of an expression or a table filed) 128.999 is not quite equal to 128.9990

Respectfully,
Vilhelm-Ion Praisach
Resita, Romania
 
You know, 2^10 = 1024 which is quite close to the magnitude of 1000 = three decimal places. So a pattern may reoccur with every 3 decimal places, even though it's not a perfect match, so this pattern may break, if you could have enough decimal places with larger float numbers. We will not be able to verify that, as VFP is limited to a precision of about 16 decimal places at max anyway, so that pattern could repeat within the range of VFP style floats.

Yes, it's fun to deep dive into the details of VFP, even just into the detail behaviour of a bug, to get to know more about it and be able to predict at what value ranges it happens. I agree absolutely, the mask plays an additional role, even the main role. I can only imagine it determines the number of decimal places converted to a string. But even if it would, I would expect something different, so it has even more influence even after conversion, perhaps. The behaviour of the mask does fail much more miserable than rounding would fail on razor edge numbers in the binary domain, eg all the cases you show are far from a razor edge difference to round up or down at some digits before the one you introduce the difference, but that's also true because of the conversion of decimal to binary and back, so the wrong rounding must have something to do with the mask, too.

You could experiment more with the natural binary values .5, .25, .125, etc. etc. instead of the decimal places, maybe then you'll find out best about edge cases.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top