[sqlite] Non-transitive numeric equality

2015-11-06 Thread Simon Slavin

On 6 Nov 2015, at 2:20pm, Wade, William  wrote:

> I have an engineering application, where double can be part of a key.

So do I, using Longitude and Latitude in GPS coordinates.  A lot of things done 
inside GPS devices amount to "List everything in this rectangle".

This is the problem.  Theoretically we are saying "You cannot test for equality 
in REAL so we should remove COLLATE for REAL numbers.".  But there are 
thousands of apps out there which use REALs in keys, get useful results fast, 
and don't care how edge cases are handled.  So we carry on as before, 
occasionally telling someone new why the carpet's a bit lumpy over by the coat 
rack.

Simon.


[sqlite] Non-transitive numeric equality

2015-11-06 Thread Wade, William
I have an engineering application, where double can be part of a key. In cases 
where I do a comparison that implies a test for equality, I don't necessarily 
care what happens in the really close cases.

SELECT x,y FROM mytable WHERE x >= 1234 AND x < 5678

There may be about a 1 records in that time range, and for engineering 
purposes when I write that I don't particularly care whether I am getting 
1, 10001 or 10002 entries.

However I do depend on getting consistent answers, and on (x >= 1234) being 
disjoint from (x < 1234) and that those two ranges cover the number line. I 
suspect that sqlite makes that kind of guarantee, at least if I explicitly cast 
values to double whenever I do an INSERT or UPDATE or WHERE, although that 
seems like an easy thing to forget to do.

However, nothing in the sqlite documentation promises that sqlite won't 
internally perform an equality test on primary keys, so it seems that I have to 
worry that if equality is not transitive, my database can be in arbitrarily bad 
shape (select gives answers that aren't even close to looking right).

Is the answer for this kind of thing to cast all of my values to double when 
feeding them to sqlite, if I want it to do math using "double" rules?

I suspect sqlite could get the "correct" answers when doing comparisons between 
two types where one type is not a superset of the other by converting both 
values to bigint rationals and comparing those (I think the sqlite numeric 
types are all representable as bigint rationals). That may be overkill (and not 
all that lite).

Regards

-Original Message-
From: Richard Hipp [mailto:d...@sqlite.org]
Sent: Thursday, November 05, 2015 8:55 AM
To: SQLite mailing list
Subject: Re: [sqlite] Non-transitive numeric equality

On 11/5/15, Zsb?n Ambrus  wrote:
>... It seems that equality of numeric values isn't transitive, when both
> integers and reals are involved...

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.

--
D. Richard Hipp
drh at sqlite.org


**
This e-mail and any attachments thereto may contain confidential information 
and/or information protected by intellectual property rights for the exclusive 
attention of the intended addressees named above. If you have received this 
transmission in error, please immediately notify the sender by return e-mail 
and delete this message and its attachments. Unauthorized use, copying or 
further full or partial distribution of this e-mail or its contents is 
prohibited.
**


[sqlite] Non-transitive numeric equality

2015-11-06 Thread Igor Tandetnik
On 11/6/2015 9:20 AM, Wade, William wrote:
> However I do depend on getting consistent answers, and on (x >= 1234) being 
> disjoint from (x < 1234) and that those two ranges cover the number line. I 
> suspect that sqlite makes that kind of guarantee, at least if I explicitly 
> cast values to double whenever I do an INSERT or UPDATE or WHERE, although 
> that seems like an easy thing to forget to do.

Declare your columns with REAL affinity ( 
http://www.sqlite.org/datatype3.html ). Such columns never contain 
integers, only floats (any attempt to insert an integer coerces it to a 
float, possibly losing precision). One of the problems in the OPs 
example is that columns have no declared type, and thus BLOB affinity 
(which pretty much means, anything goes and no conversions are performed).
-- 
Igor Tandetnik



[sqlite] Non-transitive numeric equality

2015-11-05 Thread R Smith


On 2015/11/05 4:55 PM, Richard Hipp wrote:
> On 11/5/15, Zsb?n Ambrus  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 
> 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.




[sqlite] Non-transitive numeric equality

2015-11-05 Thread Stephan Beal
On Thu, Nov 5, 2015 at 3:36 PM, Zsb?n Ambrus  wrote:

> It seems that equality of numeric values isn't transitive, when both
> integers and reals are involved.


See this really, really, really, really long thread on that topic from a
couple weeks ago for far, far, far more information than you could possible
want on the reason:

http://www.mail-archive.com/sqlite-users at 
mailinglists.sqlite.org/msg04466.html


-- 
- stephan beal
http://wanderinghorse.net/home/stephan/
http://gplus.to/sgbeal
"Freedom is sloppy. But since tyranny's the only guaranteed byproduct of
those who insist on a perfect world, freedom will have to do." -- Bigby Wolf


[sqlite] Non-transitive numeric equality

2015-11-05 Thread Zsbán Ambrus
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

Is this behavior by design?  Can this cause problems with indexes,
sorting or grouping by?

I believe the cause of this behavior is the sqlite3MemCompare private
function in the sqlite3 implementation, which compares an integer to a
real by converting the integer to a real.  The conversion can lose
precision of the integer, and as a result, the value in the 'd' row
compares equal to the value in the 'c' row, despite that the numeric
values they represent isn't equal.  Sadly, comparing an integer to a
floating point number is not easy, so I don't know an easy fix.

I ran the test above with sqlite 3.9.2 built from the amalgamation
source on windows x86_64 with gcc 4.8.3 and the following compiler
options:

gcc -march=core2 -mavx -mvzeroupper -pthread -O2 -g
-DSQLITE_OMIT_LOAD_EXTENSION=1 -o sqlite3 sqlite3.c shell.c

-- Ambrus


[sqlite] Non-transitive numeric equality

2015-11-05 Thread Richard Hipp
On 11/5/15, Zsb?n Ambrus  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 
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.

-- 
D. Richard Hipp
drh at sqlite.org