|
Derar Novice
Joined: 09 Sep 2006 Posts: 44
|
Posted: Mon Aug 02, 2010 12:00 am
[3.22] BUG: additem, %format, and decimal truncating |
This is a little obscure, but in practical terms occurs when dealing with equations that can result in long decimal trails that you want to truncate, and the result is stored in a list.
If you use additem (# or % flavour) to add a decimal value literally, as in 600.00, trailing zeros are removed. If the decimal becomes the last character, it's also removed, leaving you with an integer. The same occurs if you generate a list by going "varlist = 600.00|601.00|602.00"; the list entries are truncated to 600|601|602, and even if you create a regular variable as "var = 600.00", it's still just set to 600, without a decimal.
Using %format(2, 600) however you can assign a set float value of 600.00 to a variable. That works fine; trailing zeros are not removed. When you try to add that variable, or just a straight %format, to a list, however... that's where it gets hairy. The trailing zeros are removed, but the trailing decimal is not, leaving you with just 600. as your value. What's even more bizarre is that using json output shows you that CMud considers 600. to still be a number, but it's a different value than just 600 as an integer (still recognizes it as a float, I suppose). This causes problems, especially when you're trying to work with comparisons in the list.
Observe the results of the following:
Code: |
#LOOP 600,610 {#ADDITEM TestList %i;#SHOW %json(@TestList)}
#LOOP 600,610 {#ADDITEM TestList %format(2, %i);#SHOW %json(@TestList)}
#SHOW %item(@TestList, 12)
#SHOW %ismember(%item(@TestList, 12), @TestList)
TestList = %null
#LOOP 600,610 {#ADDITEM TestList %format(2, %i);#SHOW %json(@TestList)}
#SHOW %item(@TestList, 11)
#SHOW %ismember(%item(@TestList, 11), @TestList)
|
Which outputs:
Code: |
[600]
[600,601]
[600,601,602]
[600,601,602,603]
[600,601,602,603,604]
[600,601,602,603,604,605]
[600,601,602,603,604,605,606]
[600,601,602,603,604,605,606,607]
[600,601,602,603,604,605,606,607,608]
[600,601,602,603,604,605,606,607,608,609]
[600,601,602,603,604,605,606,607,608,609,610]
[600,601,602,603,604,605,606,607,608,609,610,600.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.,605.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.,605.,606.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.,605.,606.,607.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.,605.,606.,607.,608.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.,605.,606.,607.,608.,609.]
[600,601,602,603,604,605,606,607,608,609,610,600.,601.,602.,603.,604.,605.,606.,607.,608.,609.,610.]
600
1
[600.]
[600.,601.]
[600.,601.,602.]
[600.,601.,602.,603.]
[600.,601.,602.,603.,604.]
[600.,601.,602.,603.,604.,605.]
[600.,601.,602.,603.,604.,605.,606.]
[600.,601.,602.,603.,604.,605.,606.,607.]
[600.,601.,602.,603.,604.,605.,606.,607.,608.]
[600.,601.,602.,603.,604.,605.,606.,607.,608.,609.]
[600.,601.,602.,603.,604.,605.,606.,607.,608.,609.,610.]
610
0
|
The way this presented for me to look into was that last bit there... how %item drops the decimal when it pulls the list entry, but when you use %ismember to compare back into the list, they're no longer the same value.
The bug, I would say, is in the failure to drop the decimal, but from a visibilty standpoint, it would be nice if lists didn't automatically truncate decimal values at all, even to eliminate trailing 0s, if they're passed a specific length of decimal trail; they didn't in 3.17, iirc (my script worked and compared properly, at any rate, but 3.17 expired now, so i can't verify :P). |
|
|
|
Derar Novice
Joined: 09 Sep 2006 Posts: 44
|
Posted: Mon Aug 02, 2010 1:51 am |
It would also appear that %ismember checking against a decimal value is just flat-out not working, as well; seems like there's a good bet this is tied into how the new lists are handling numbers overall (maybe to do with the . nesting syntax?), hence the post in continuation of my original report.
Try:
Code: |
TestList = 1.5|2.5|3.5
#SHOW %json(@TestList)
#SHOW %ismember(1.5, @TestList)
#SHOW %ismember("1.5", @TestList)
TestList = 1|2|3
#SHOW %json(@TestList)
#SHOW %ismember(3, @TestList)
|
Get:
Code: |
[1.5,2.5,3.5]
0
0
[1,2,3]
3
|
|
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Aug 02, 2010 4:30 pm |
First, your syntax for making a list is wrong. You are doing this:
Code: |
TestList = 1.5|2.5|3.5 |
That is WRONG and may break at any point in the future. To specify a string list, you MUST put {} around it, like this:
Code: |
TestList = {1.5|2.5|3.5} |
Regarding the issue with floating point, part of this issue is related to the fact that floating point values cannot be represented by computers perfectly when using a binary floating point format. When you store 600.0 in a variable, it is stored as a double-precision floating point value using the binary format implemented by the Intel chip-set in your computer. Internally, this might end up being 600.000001 or something like that. That is because you are working in a base-10 format, while the computer itself is working in a binary (base-2) format and with floating point there is no perfect representation of decimal values in binary.
When CMUD sees you try to compare two floating point values, like "#IF (@var = 3.5)" CMUD actually doesn't perform an exact equality test. Instead, CMUD performs a floating point value comparison more like this: "if abs(@var-3.5)<0.000001" (note that CMUD doesn't explicitly use 0.00001, but uses a delta value based upon double-precision accuracy).
When using %ismember, you are performing a direct equality test using a *string* key value. So if the internal value is really 600.000001 and you do %ismember(600,@var), it will fail because there is not a direct match. I'd need to look at the low-level code in the 3rd party JSON parser to see exactly how it handles this, but it's not something I'm doing directly in CMUD so I'm not sure it can be fixed.
These kind of floating point issues are common in all computer programming languages. Depending upon exact equality tests of floating-point values is always a problem and something you should avoid whenever possible.
You should be able to force CMUD to store a string value rather than a floating point value using the %string function or by putting " quotes around the floating point values. |
|
|
|
Derar Novice
Joined: 09 Sep 2006 Posts: 44
|
Posted: Mon Aug 02, 2010 6:55 pm |
It looks like %string and "" methods aren't allowing a forced string insertion of a number value either:
Code: |
TestList = {"100"|"20"}
#SHOW %json(@TestList)
TestList = {%string(100)|%string(20)}
#SHOW %json(@TestList)
TestList = {%string(100)|%string(20)|"Test"}
#SHOW %json(@TestList)
TestList = %additem(%string(50), @TestList)
#SHOW %json(@TestList)
TestList = "100"|"20"
#SHOW %json(@TestList)
TestList = %replaceitem(24, 2, @TestList)
TestList = %replaceitem(100, 1, @TestList)
#SHOW %json(@TestList)
#SHOW (%item(@TestList, 1) + %item(@TestList, 2))
|
(I know the last list declaration is missing braces; intentional here)
Output:
Code: |
[100,20]
[100,20]
[100,20,"Test"]
[100,20,"Test",50]
[100,20]
[100,"24"]
["100","24"]
10024
|
Ironically, the only way to forcibly add a number as a string seems to be by the %replaceitem bug I reported here.
There definitely seem to be some auto-typing issues at play here that are causing havoc on scripts that I run using lists and evaluations that previously worked fine in 3.17. I vaguely remember reading in one post of yours that prior to the JSON addition, CMud had no real way to distinguish between numbers and strings being stored in string lists, which is probably why %ismember looking for floating values was never an issue, since it was always a string comparison.
Basically, before, we were able to operate both mathematically and on the list itself without any messing around. Now we will need to explicitly convert list values into numeric to work with them via math, and then convert them back into string values to store them in the list in a manageable way, or even to compare them to existing members of the list. If you're used to strongly typed languages it's not all that onerous, but it really does add a lot of (previously) unnecessary extra script code requirements and I can see that being a turn-off for some users. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Tue Aug 03, 2010 4:46 pm |
Hmm, that looks like another bug. I'll add that to the list.
|
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Fri Aug 20, 2010 7:22 pm |
I've got this working better now for the next version. However, I found another bug in your test script at the end. When using %replaceitem(24...) there was a bug in v3.22 that was always treating this as a string value. This is fixed in v3.23. So your above example will show:
for the last couple of tests. So in v3.23, you need to put the 24 in " quotes, like:
Code: |
TestList = "100"|"20"
#SHOW %json(@TestList)
TestList = %replaceitem("24", 2, @TestList)
TestList = %replaceitem("100", 1, @TestList)
#SHOW %json(@TestList)
#SHOW (%item(@TestList, 1) + %item(@TestList, 2)) |
to still get the
result. This should make sense to you, but I wanted to be sure and point it out. In any case, 3.23 should properly respect integers, floating point and string values, along with the %int(), %float() and %string() conversion functions when adding items to lists and tables. |
|
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|