## 1. Floating Point Arithmetic, Numeric Comparisons and NaN
The rules of floating point arithmetic are laid down in the IEEE 754 standard. They are built into the hardware of just about every computer that supports floating point and anyone who wants to learn a new language is likely to find the arithmetic rules easy to get to grips with because they are the same across the board.
The LiveCode engine, in nearly every case, follows the standard rules. The engine is written in C++, and the numeric expressions are evaluated using the corresponding C++ operators and functions, thus guaranteeing compliance with IEEE 754. One of the standard rules involves the special value NaN, which is actually a range of values used for error detection and other purposes. The standard says that when NaN appears on either or both sides of an arithmetic comparison operator all the comparison operators must return false, except for <> which must return true. This may seem non-intuitive at first; nonetheless it’s an integral part of the standard.
I said that LiveCode follows the IEEE 754 rules in “nearly every case” because the LiveCode engine does not correctly follow the rules regarding numeric comparisons and NaN. I submit that this is an error in LiveCode because it is out of step with the rest of the world. In saying this I am only expressing my support for bug report 22274 which has already addressed the issue.
For some further reading on NaN, see https://ntgard.medium.com/why-nan-nan-3d41af988d30. That blog entry discusses NaN in the context of JavaScript but because of the universal nature of floating point arithmetic it is just as valid for LiveCode.
## 2. Perils of Numeric Comparisons
When strings like NAN and INF appear in a collection of data the < and > operators will not work as one might at first expect because these strings will be converted to numbers. The question that started this thread gave the use case of working with Australian stock market codes, which Wikipedia describes as three-character strings with alphanumeric characters as the first and third characters, and an alphabetic character between them. Different stock exchanges have different rules but if we stick with the Australian use case here are some examples of codes that might or might not be in use yet but could be some day. The first five of these are of the digit-letter-digit form and they are only five out of a total of 116 similar possibilities.
Code: Select all
0X0, 0XA, 4E3, 5E2, 6E1, INF, NAN
If we consider just the (4E3, 5E2, 6E1) set, then under the usual rules for weakly typed languages they can be taken as numbers so they will be, and we find that
6E1 < 5E2 < 4E3 (in decimal, 60 < 500 < 4000)
But consider the very similar set with H instead of E. These cannot be taken as numbers so they will be compared as strings and we find that
4H3 < 5H2 < 6H1
The order appears reversed but this is not an error. It is simply a consequence of the rules of the language.
## 3. String Comparisons
The issue of comparing string values (for example to see which of two strings would appear earlier in a dictionary) is (IMHO) somethng that’s made more difficult by LiveCode’s lack of a dedicated string comparison operator. There are (at least) two problems:
1. Because the LiveCode comparison operators convert strings to numbers where possible, the idea of alphabetical ordering breaks in the face of values that can be interpreted as numbers. A useful string comparison method must suppress the automatic conversion of these values.
2. There are many ways of comparing strings. LiveCode’s sort command, for example, allows a sortType parameter which can be international, numeric, datetime, text or binary. Other languages offer other possibilities, including what’s sometimes known as dictionary sorting where the string A20 will sort before the string A100.
I believe LiveCode would benefit from a new string comparison operator. One possibility would be
this syntax:
Code: Select all
<string> sorts [sortType] [by sortKey] [not] before|equal|after <string>
## 4. Summary and Workround
I would like to see string comparison implemented along the lines I have described, but in the meantime it is still possible to enforce string comparison with the construct
Code: Select all
put ("x" & string1) > ("x" & string2)