script might not be the fault of SQLite. FossilOrigin-Name: 65efcb0a2ed49fa2fd747b5f034d976ed3cb4a01a185bcada70bf8a5208f3841
187 lines
6.2 KiB
SQL
187 lines
6.2 KiB
SQL
#!sqlite3
|
|
#
|
|
# 2026-03-01
|
|
#
|
|
# The author disclaims copyright to this source code. In place of
|
|
# a legal notice, here is a blessing:
|
|
#
|
|
# May you do good and not evil.
|
|
# May you find forgiveness for yourself and forgive others.
|
|
# May you share freely, never taking more than you give.
|
|
#
|
|
#***********************************************************************
|
|
#
|
|
# Floating-point <-> text conversions
|
|
#
|
|
# FAILURES IN THIS SCRIPT ARE NOT NECESSARILY THE FAULT OF SQLITE.
|
|
#
|
|
# Some of the tests below use the system strtod() function as
|
|
# an oracle of truth. These tests assume that the system strtod()
|
|
# is always correct. That is the case for Win11, Macs, most Linux
|
|
# boxes and so forth. But it possible to find a machine for which
|
|
# is not true. (One example, is Macs from around 2005.) On such
|
|
# machines, some of these tests might fail.
|
|
#
|
|
# So, in other words, a failure in any of the tests below does not
|
|
# necessarily mean that SQLite is wrong. It might mean that the
|
|
# strtod() function in the standard library of the machine on which
|
|
# the test is running is wrong.
|
|
#
|
|
|
|
# Verify that binary64 -> text -> binary64 conversions round-trip
|
|
# successfully for 98,256 different edge-case binary64 values. The
|
|
# query result is all cases that do not round-trip without change,
|
|
# and so the query result should be an empty set.
|
|
#
|
|
.testcase 100
|
|
.mode list
|
|
WITH
|
|
i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<15),
|
|
i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe),
|
|
i3(k) AS (VALUES(0x0000000000000000),
|
|
(0x000ffffffffffff0),
|
|
(0x0008080808080800)),
|
|
fpint(n) AS (SELECT (j<<52)+i+k FROM i2, i1, i3),
|
|
fp(n,r) AS (SELECT n, ieee754_from_int(n) FROM fpint)
|
|
SELECT n, r FROM fp WHERE r<>(0.0 + (r||''));
|
|
.check ''
|
|
|
|
# Another batch of 106,444 edge cases: All postiive floating point
|
|
# values that have only a single bit set in the mantissa part of the
|
|
# number.
|
|
#
|
|
.testcase 110
|
|
WITH
|
|
i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<51),
|
|
i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe),
|
|
fpint(n) AS (SELECT (j<<52)+(1<<i) FROM i2, i1),
|
|
fp(n,r) AS (SELECT n, ieee754_from_int(n) FROM fpint)
|
|
SELECT n, r FROM fp WHERE r<>(0.0 + (r||''));
|
|
.check ''
|
|
|
|
# Verify that text -> binary64 conversions agree with system strtod().
|
|
# for 98,256 different edge-cases.
|
|
#
|
|
.testcase 200
|
|
.mode list
|
|
WITH
|
|
i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<15),
|
|
i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe),
|
|
i3(k) AS (VALUES(0x0000000000000000),
|
|
(0x000ffffffffffff0),
|
|
(0x0008080808080800)),
|
|
fpint(n) AS (SELECT (j<<52)+i+k FROM i2, i1, i3),
|
|
fp(r) AS (SELECT ieee754_from_int(n) FROM fpint)
|
|
SELECT r FROM fp WHERE r<>strtod(r||'');
|
|
.check ''
|
|
|
|
|
|
# Another batch of 106,444 edge cases: All postiive floating point
|
|
# values that have only a single bit set in the mantissa part of the
|
|
# number.
|
|
#
|
|
.testcase 210
|
|
WITH
|
|
i1(i) AS (VALUES(0) UNION ALL SELECT i+1 FROM i1 WHERE i<51),
|
|
i2(j) AS (VALUES(0) UNION ALL SELECT j+1 FROM i2 WHERE j<0x7fe),
|
|
fpint(n) AS (SELECT (j<<52)+(1<<i) FROM i2, i1),
|
|
fp(r) AS (SELECT ieee754_from_int(n) FROM fpint)
|
|
SELECT r FROM fp WHERE r<>strtod(r||'');
|
|
.check ''
|
|
|
|
# Comparing SQLite's text-to-double conversion against strtod()
|
|
# for 200,000 random floating-point literals.
|
|
#
|
|
.param set $N 50_000
|
|
.testcase 300
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
VALUES(1,'1234.5789')
|
|
UNION ALL
|
|
SELECT n+1, format('%.*s.%.*se%+d',
|
|
(n%3)+1,
|
|
random()%1000,
|
|
abs(random()%16)+1,
|
|
abs(random()),
|
|
random()%308)
|
|
FROM fp WHERE n<$N
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 301
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
VALUES(1,'1234.5789')
|
|
UNION ALL
|
|
SELECT n+1, format('%.*s.%.*s',
|
|
(n%3)+1,
|
|
random()%1000,
|
|
abs(random()%16)+1,
|
|
abs(random()))
|
|
FROM fp WHERE n<$N
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 302
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
VALUES(1,'1234.5789')
|
|
UNION ALL
|
|
SELECT n+1, format('%.*s.%.*s',
|
|
abs(random()%7)+1,
|
|
random(),
|
|
abs(random()%10)+1,
|
|
abs(random()))
|
|
FROM fp WHERE n<$N
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 303
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
VALUES(1,'1234.5789')
|
|
UNION ALL
|
|
SELECT n+1, format('%de%+03d',
|
|
random(),
|
|
random()%308)
|
|
FROM fp WHERE n<$N
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
|
|
# Another 500,000 comparisions between SQLite and strtod() from completely
|
|
# random floating point literals.
|
|
#
|
|
.testcase 310
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
UNION ALL
|
|
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
FROM fp WHERE n<$N*2
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 311
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
UNION ALL
|
|
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
FROM fp WHERE n<$N*2
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 312
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
UNION ALL
|
|
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
FROM fp WHERE n<$N*2
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 313
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
UNION ALL
|
|
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
FROM fp WHERE n<$N*2
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|
|
.testcase 314
|
|
WITH RECURSIVE fp(n,x) AS MATERIALIZED (
|
|
SELECT 1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
UNION ALL
|
|
SELECT n+1, format('%+.*g',abs(random()%18), ieee754_from_int(random()))
|
|
FROM fp WHERE n<$N*2
|
|
) SELECT x FROM fp WHERE (x+0.0)<>strtod(x);
|
|
.check ''
|