On 2015/11/05 4:55 PM, Richard Hipp wrote: > On 11/5/15, Zsb?n Ambrus <ambrus at math.bme.hu> wrote: >> Dear SQLite, >> >> It seems that equality of numeric values isn't transitive, when both >> integers and reals are involved. Here's an example output from the >> shell, which shows that the numeric value in the 'c' row is equal to >> both the value in the 'b' and the 'd' rows, but the value in the 'b' >> row isn't equal to the value in the 'd' row. Neither null values nor >> collations seem to be involved here. >> >> SQLite version 3.9.2 2015-11-02 18:31:45 >> Enter ".help" for usage hints. >> Connected to a transient in-memory database. >> Use ".open FILENAME" to reopen on a persistent database. >> sqlite> create table tb(n, v); >> sqlite> insert into tb(n, v) values ('b', 1<<58), ('c', (1<<58) + >> 1e-7), ('d', (1<<58) + 1); >> sqlite> select n, v, typeof(v) from tb; >> b|288230376151711744|integer >> c|2.88230376151712e+17|real >> d|288230376151711745|integer >> sqlite> select l.n, r.n, l.v = r.v from tb as l, tb as r; >> b|b|1 >> b|c|1 >> b|d|0 >> c|b|1 >> c|c|1 >> c|d|1 >> d|b|0 >> d|c|1 >> d|d|1 >> sqlite> .quit > The following C program gives the same answer (using gcc 4.8.4 on ubuntu): > > #include <stdio.h> > typedef long long int i64; > int main(int argc, char **argv){ > i64 b = 1LL << 58; > double c = (1LL << 58) + 1e-7; > i64 d = (1LL << 58) + 1; > printf("b==b: %d\n", b==b); > printf("b==c: %d\n", b==c); > printf("b==d: %d\n", b==d); > printf("c==b: %d\n", c==b); > printf("c==c: %d\n", c==c); > printf("c==d: %d\n", c==d); > printf("d==b: %d\n", d==b); > printf("d==c: %d\n", d==c); > printf("d==d: %d\n", d==d); > return 0; > } > > >> Can this cause problems with indexes, >> sorting or grouping by? >> > You should not compare floating-point numbers for equality. > Floating-point numbers are, by definition, approximations. When you > compare floating-point numbers, therefore, you get an approximate > answer. >
fwiw - I don't get the same result, here is the same script running in Win32-SQLitespeed-via-SQLite-3.9.1-DLL (the standard pre-compiled one from sqlite.org) on an in-memory Database, This one seems to magically get it right: -- 2015-11-05 16:41:54.666 | [Info] Script Initialized, Started executing... -- ================================================================================================ create table tb(n, v); insert into tb(n, v) values ('b', 1<<58), ('c', (1<<58) + 1e-7), ('d', (1<<58) + 1); select n, v, typeof(v) from tb; -- n | v | typeof(v) -- ----- | ---------------------- | --------- -- b | 288230376151711744 | integer -- c | 2.88230376151712e+17 | real -- d | 288230376151711745 | integer select l.n, r.n, l.v = r.v from tb as l, tb as r; -- n | n | l.v = r.v -- ----- | ----- | --------- -- b | b | 1 -- b | c | 1 -- b | d | 0 -- c | b | 1 -- c | c | 1 -- c | d | 0 -- d | b | 0 -- d | c | 0 -- d | d | 1 -- 2015-11-05 16:41:54.675 | [Success] Script Success. And to answer the OP's other question - This doesn't matter, a Primary key using FLOAT values is rather risky, but any float that isn't represented exactly the same as another will have a different bit pattern. Mixing floats and ints in a PK however, might be disastrous.