--
-- FLOAT8
--
CREATE TABLE FLOAT8_TBL (
    f1 float8
);

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('    0.0   ');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('1004.30  ');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('   -34.84');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('1.2345678901234e+200');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('1.2345678901234e-200');

-- test for underflow and overflow handling
SELECT
    '10e400'::float8;

SELECT
    '-10e400'::float8;

SELECT
    '10e-400'::float8;

SELECT
    '-10e-400'::float8;

-- test smallest normalized input
SELECT
    float8send('2.2250738585072014E-308'::float8);

-- bad input
INSERT INTO FLOAT8_TBL (f1)
    VALUES ('');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('     ');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('xyz');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('5.0.0');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('5 . 0');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('5.   0');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('    - 3');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('123           5');

-- special inputs
SELECT
    'NaN'::float8;

SELECT
    'nan'::float8;

SELECT
    '   NAN  '::float8;

SELECT
    'infinity'::float8;

SELECT
    '          -INFINiTY   '::float8;

-- bad special inputs
SELECT
    'N A N'::float8;

SELECT
    'NaN x'::float8;

SELECT
    ' INFINITY    x'::float8;

SELECT
    'Infinity'::float8 + 100.0;

SELECT
    'Infinity'::float8 / 'Infinity'::float8;

SELECT
    'nan'::float8 / 'nan'::float8;

SELECT
    'nan'::numeric::float8;

SELECT
    '' AS five,
    *
FROM
    FLOAT8_TBL;

SELECT
    '' AS four,
    f.*
FROM
    FLOAT8_TBL f
WHERE
    f.f1 <> '1004.3';

SELECT
    '' AS one,
    f.*
FROM
    FLOAT8_TBL f
WHERE
    f.f1 = '1004.3';

SELECT
    '' AS three,
    f.*
FROM
    FLOAT8_TBL f
WHERE
    '1004.3' > f.f1;

SELECT
    '' AS three,
    f.*
FROM
    FLOAT8_TBL f
WHERE
    f.f1 < '1004.3';

SELECT
    '' AS four,
    f.*
FROM
    FLOAT8_TBL f
WHERE
    '1004.3' >= f.f1;

SELECT
    '' AS four,
    f.*
FROM
    FLOAT8_TBL f
WHERE
    f.f1 <= '1004.3';

SELECT
    '' AS three,
    f.f1,
    f.f1 * '-10' AS x
FROM
    FLOAT8_TBL f
WHERE
    f.f1 > '0.0';

SELECT
    '' AS three,
    f.f1,
    f.f1 + '-10' AS x
FROM
    FLOAT8_TBL f
WHERE
    f.f1 > '0.0';

SELECT
    '' AS three,
    f.f1,
    f.f1 / '-10' AS x
FROM
    FLOAT8_TBL f
WHERE
    f.f1 > '0.0';

SELECT
    '' AS three,
    f.f1,
    f.f1 - '-10' AS x
FROM
    FLOAT8_TBL f
WHERE
    f.f1 > '0.0';

SELECT
    '' AS one,
    f.f1 ^ '2.0' AS square_f1
FROM
    FLOAT8_TBL f
WHERE
    f.f1 = '1004.3';

-- absolute value
SELECT
    '' AS five,
    f.f1,
    @f.f1 AS abs_f1
FROM
    FLOAT8_TBL f;

-- truncate
SELECT
    '' AS five,
    f.f1,
    trunc(f.f1) AS trunc_f1
FROM
    FLOAT8_TBL f;

-- round
SELECT
    '' AS five,
    f.f1,
    round(f.f1) AS round_f1
FROM
    FLOAT8_TBL f;

-- ceil / ceiling
SELECT
    ceil(f1) AS ceil_f1
FROM
    float8_tbl f;

SELECT
    ceiling(f1) AS ceiling_f1
FROM
    float8_tbl f;

-- floor
SELECT
    floor(f1) AS floor_f1
FROM
    float8_tbl f;

-- sign
SELECT
    sign(f1) AS sign_f1
FROM
    float8_tbl f;

-- avoid bit-exact output here because operations may not be bit-exact.
SET extra_float_digits = 0;

-- square root
SELECT
    sqrt(float8 '64') AS eight;

SELECT
    |/ float8 '64' AS eight;

SELECT
    '' AS three,
    f.f1,
    |/ f.f1 AS sqrt_f1
FROM
    FLOAT8_TBL f
WHERE
    f.f1 > '0.0';

-- power
SELECT
    power(float8 '144', float8 '0.5');

SELECT
    power(float8 'NaN', float8 '0.5');

SELECT
    power(float8 '144', float8 'NaN');

SELECT
    power(float8 'NaN', float8 'NaN');

SELECT
    power(float8 '-1', float8 'NaN');

SELECT
    power(float8 '1', float8 'NaN');

SELECT
    power(float8 'NaN', float8 '0');

-- take exp of ln(f.f1)
SELECT
    '' AS three,
    f.f1,
    exp(ln(f.f1)) AS exp_ln_f1
FROM
    FLOAT8_TBL f
WHERE
    f.f1 > '0.0';

-- cube root
SELECT
    ||/ float8 '27' AS three;

SELECT
    '' AS five,
    f.f1,
    ||/ f.f1 AS cbrt_f1
FROM
    FLOAT8_TBL f;

SELECT
    '' AS five,
    *
FROM
    FLOAT8_TBL;

UPDATE
    FLOAT8_TBL
SET
    f1 = FLOAT8_TBL.f1 * '-1'
WHERE
    FLOAT8_TBL.f1 > '0.0';

SELECT
    '' AS bad,
    f.f1 * '1e200'
FROM
    FLOAT8_TBL f;

SELECT
    '' AS bad,
    f.f1 ^ '1e200'
FROM
    FLOAT8_TBL f;

SELECT
    0 ^ 0 + 0 ^ 1 + 0 ^ 0.0 + 0 ^ 0.5;

SELECT
    '' AS bad,
    ln(f.f1)
FROM
    FLOAT8_TBL f
WHERE
    f.f1 = '0.0';

SELECT
    '' AS bad,
    ln(f.f1)
FROM
    FLOAT8_TBL f
WHERE
    f.f1 < '0.0';

SELECT
    '' AS bad,
    exp(f.f1)
FROM
    FLOAT8_TBL f;

SELECT
    '' AS bad,
    f.f1 / '0.0'
FROM
    FLOAT8_TBL f;

SELECT
    '' AS five,
    *
FROM
    FLOAT8_TBL;

-- hyperbolic functions
-- we run these with extra_float_digits = 0 too, since different platforms
-- tend to produce results that vary in the last place.
SELECT
    sinh (float8 '1');

SELECT
    cosh (float8 '1');

SELECT
    tanh (float8 '1');

SELECT
    asinh (float8 '1');

SELECT
    acosh (float8 '2');

SELECT
    atanh (float8 '0.5');

-- test Inf/NaN cases for hyperbolic functions
SELECT
    sinh (float8 'infinity');

SELECT
    sinh (float8 '-infinity');

SELECT
    sinh (float8 'nan');

SELECT
    cosh (float8 'infinity');

SELECT
    cosh (float8 '-infinity');

SELECT
    cosh (float8 'nan');

SELECT
    tanh (float8 'infinity');

SELECT
    tanh (float8 '-infinity');

SELECT
    tanh (float8 'nan');

SELECT
    asinh (float8 'infinity');

SELECT
    asinh (float8 '-infinity');

SELECT
    asinh (float8 'nan');

-- acosh(Inf) should be Inf, but some mingw versions produce NaN, so skip test
-- SELECT acosh(float8 'infinity');
SELECT
    acosh (float8 '-infinity');

SELECT
    acosh (float8 'nan');

SELECT
    atanh (float8 'infinity');

SELECT
    atanh (float8 '-infinity');

SELECT
    atanh (float8 'nan');

RESET extra_float_digits;

-- test for over- and underflow
INSERT INTO FLOAT8_TBL (f1)
    VALUES ('10e400');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('-10e400');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('10e-400');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('-10e-400');

-- maintain external table consistency across platforms
-- delete all values and reinsert well-behaved ones
DELETE FROM FLOAT8_TBL;

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('0.0');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('-34.84');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('-1004.30');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('-1.2345678901234e+200');

INSERT INTO FLOAT8_TBL (f1)
    VALUES ('-1.2345678901234e-200');

SELECT
    '' AS five,
    *
FROM
    FLOAT8_TBL;

-- test edge-case coercions to integer
SELECT
    '32767.4'::float8::int2;

SELECT
    '32767.6'::float8::int2;

SELECT
    '-32768.4'::float8::int2;

SELECT
    '-32768.6'::float8::int2;

SELECT
    '2147483647.4'::float8::int4;

SELECT
    '2147483647.6'::float8::int4;

SELECT
    '-2147483648.4'::float8::int4;

SELECT
    '-2147483648.6'::float8::int4;

SELECT
    '9223372036854773760'::float8::int8;

SELECT
    '9223372036854775807'::float8::int8;

SELECT
    '-9223372036854775808.5'::float8::int8;

SELECT
    '-9223372036854780000'::float8::int8;

-- test exact cases for trigonometric functions in degrees
SELECT
    x,
    sind (x),
    sind (x) IN (- 1, - 0.5, 0, 0.5, 1) AS sind_exact
FROM (
    VALUES (0),
        (30),
        (90),
        (150),
        (180),
        (210),
        (270),
        (330),
        (360)) AS t (x);

SELECT
    x,
    cosd (x),
    cosd (x) IN (- 1, - 0.5, 0, 0.5, 1) AS cosd_exact
FROM (
    VALUES (0),
        (60),
        (90),
        (120),
        (180),
        (240),
        (270),
        (300),
        (360)) AS t (x);

SELECT
    x,
    tand (x),
    tand (x) IN ('-Infinity'::float8, - 1, 0, 1, 'Infinity'::float8) AS tand_exact,
    cotd (x),
    cotd (x) IN ('-Infinity'::float8, - 1, 0, 1, 'Infinity'::float8) AS cotd_exact
FROM (
    VALUES (0),
        (45),
        (90),
        (135),
        (180),
        (225),
        (270),
        (315),
        (360)) AS t (x);

SELECT
    x,
    asind (x),
    asind (x) IN (- 90, - 30, 0, 30, 90) AS asind_exact,
    acosd (x),
    acosd (x) IN (0, 60, 90, 120, 180) AS acosd_exact
FROM (
    VALUES (- 1),
        (- 0.5),
        (0),
        (0.5),
        (1)) AS t (x);

SELECT
    x,
    atand (x),
    atand (x) IN (- 90, - 45, 0, 45, 90) AS atand_exact
FROM (
    VALUES ('-Infinity'::float8),
        (- 1),
        (0),
        (1),
        ('Infinity'::float8)) AS t (x);

SELECT
    x,
    y,
    atan2d (y, x),
    atan2d (y, x) IN (- 90, 0, 90, 180) AS atan2d_exact
FROM (
    SELECT
        10 * cosd (a),
        10 * sind (a)
    FROM
        generate_series(0, 360, 90) AS t (a)) AS t (x,
        y);

--
-- test output (and round-trip safety) of various values.
-- To ensure we're testing what we think we're testing, start with
-- float values specified by bit patterns (as a useful side effect,
-- this means we'll fail on non-IEEE platforms).
CREATE TYPE xfloat8;

CREATE FUNCTION xfloat8in (cstring)
    RETURNS xfloat8 IMMUTABLE STRICT
    LANGUAGE internal
    AS 'int8in';

CREATE FUNCTION xfloat8out (xfloat8)
    RETURNS cstring IMMUTABLE STRICT
    LANGUAGE internal
    AS 'int8out';

CREATE TYPE xfloat8 (
    input = xfloat8in,
    output = xfloat8out,
    LIKE = float8
);

CREATE cast (xfloat8 AS float8) WITHOUT FUNCTION;

CREATE cast (float8 AS xfloat8) WITHOUT FUNCTION;

CREATE cast (xfloat8 AS bigint) WITHOUT FUNCTION;

CREATE cast (bigint AS xfloat8) WITHOUT FUNCTION;

-- float8: seeeeeee eeeeeeee eeeeeeee mmmmmmmm mmmmmmmm(x4)
-- we don't care to assume the platform's strtod() handles subnormals
-- correctly; those are "use at your own risk". However we do test
-- subnormal outputs, since those are under our control.
WITH testdata (
    bits
) AS (
    VALUES
        -- small subnormals
        (x '0000000000000001'),
        (x '0000000000000002'),
        (x '0000000000000003'),
        (x '0000000000001000'),
        (x '0000000100000000'),
        (x '0000010000000000'),
        (x '0000010100000000'),
        (x '0000400000000000'),
        (x '0000400100000000'),
        (x '0000800000000000'),
        (x '0000800000000001'),
        -- these values taken from upstream testsuite
        (x '00000000000f4240'),
        (x '00000000016e3600'),
        (x '0000008cdcdea440'),
        -- borderline between subnormal and normal
        (x '000ffffffffffff0'),
        (x '000ffffffffffff1'),
        (x '000ffffffffffffe'),
        (x '000fffffffffffff'))
SELECT
    float8send(flt) AS ibits,
    flt
FROM (
    SELECT
        bits::bigint::xfloat8::float8 AS flt
    FROM
        testdata offset 0) s;

-- round-trip tests
WITH testdata (
    bits
) AS (
    VALUES (x '0000000000000000'),
        -- smallest normal values
        (x '0010000000000000'),
        (x '0010000000000001'),
        (x '0010000000000002'),
        (x '0018000000000000'),
        --
        (x '3ddb7cdfd9d7bdba'),
        (x '3ddb7cdfd9d7bdbb'),
        (x '3ddb7cdfd9d7bdbc'),
        (x '3e112e0be826d694'),
        (x '3e112e0be826d695'),
        (x '3e112e0be826d696'),
        (x '3e45798ee2308c39'),
        (x '3e45798ee2308c3a'),
        (x '3e45798ee2308c3b'),
        (x '3e7ad7f29abcaf47'),
        (x '3e7ad7f29abcaf48'),
        (x '3e7ad7f29abcaf49'),
        (x '3eb0c6f7a0b5ed8c'),
        (x '3eb0c6f7a0b5ed8d'),
        (x '3eb0c6f7a0b5ed8e'),
        (x '3ee4f8b588e368ef'),
        (x '3ee4f8b588e368f0'),
        (x '3ee4f8b588e368f1'),
        (x '3f1a36e2eb1c432c'),
        (x '3f1a36e2eb1c432d'),
        (x '3f1a36e2eb1c432e'),
        (x '3f50624dd2f1a9fb'),
        (x '3f50624dd2f1a9fc'),
        (x '3f50624dd2f1a9fd'),
        (x '3f847ae147ae147a'),
        (x '3f847ae147ae147b'),
        (x '3f847ae147ae147c'),
        (x '3fb9999999999999'),
        (x '3fb999999999999a'),
        (x '3fb999999999999b'),
        -- values very close to 1
        (x '3feffffffffffff0'),
        (x '3feffffffffffff1'),
        (x '3feffffffffffff2'),
        (x '3feffffffffffff3'),
        (x '3feffffffffffff4'),
        (x '3feffffffffffff5'),
        (x '3feffffffffffff6'),
        (x '3feffffffffffff7'),
        (x '3feffffffffffff8'),
        (x '3feffffffffffff9'),
        (x '3feffffffffffffa'),
        (x '3feffffffffffffb'),
        (x '3feffffffffffffc'),
        (x '3feffffffffffffd'),
        (x '3feffffffffffffe'),
        (x '3fefffffffffffff'),
        (x '3ff0000000000000'),
        (x '3ff0000000000001'),
        (x '3ff0000000000002'),
        (x '3ff0000000000003'),
        (x '3ff0000000000004'),
        (x '3ff0000000000005'),
        (x '3ff0000000000006'),
        (x '3ff0000000000007'),
        (x '3ff0000000000008'),
        (x '3ff0000000000009'),
        --
        (x '3ff921fb54442d18'),
        (x '4005bf0a8b14576a'),
        (x '400921fb54442d18'),
        --
        (x '4023ffffffffffff'),
        (x '4024000000000000'),
        (x '4024000000000001'),
        (x '4058ffffffffffff'),
        (x '4059000000000000'),
        (x '4059000000000001'),
        (x '408f3fffffffffff'),
        (x '408f400000000000'),
        (x '408f400000000001'),
        (x '40c387ffffffffff'),
        (x '40c3880000000000'),
        (x '40c3880000000001'),
        (x '40f869ffffffffff'),
        (x '40f86a0000000000'),
        (x '40f86a0000000001'),
        (x '412e847fffffffff'),
        (x '412e848000000000'),
        (x '412e848000000001'),
        (x '416312cfffffffff'),
        (x '416312d000000000'),
        (x '416312d000000001'),
        (x '4197d783ffffffff'),
        (x '4197d78400000000'),
        (x '4197d78400000001'),
        (x '41cdcd64ffffffff'),
        (x '41cdcd6500000000'),
        (x '41cdcd6500000001'),
        (x '4202a05f1fffffff'),
        (x '4202a05f20000000'),
        (x '4202a05f20000001'),
        (x '42374876e7ffffff'),
        (x '42374876e8000000'),
        (x '42374876e8000001'),
        (x '426d1a94a1ffffff'),
        (x '426d1a94a2000000'),
        (x '426d1a94a2000001'),
        (x '42a2309ce53fffff'),
        (x '42a2309ce5400000'),
        (x '42a2309ce5400001'),
        (x '42d6bcc41e8fffff'),
        (x '42d6bcc41e900000'),
        (x '42d6bcc41e900001'),
        (x '430c6bf52633ffff'),
        (x '430c6bf526340000'),
        (x '430c6bf526340001'),
        (x '4341c37937e07fff'),
        (x '4341c37937e08000'),
        (x '4341c37937e08001'),
        (x '4376345785d89fff'),
        (x '4376345785d8a000'),
        (x '4376345785d8a001'),
        (x '43abc16d674ec7ff'),
        (x '43abc16d674ec800'),
        (x '43abc16d674ec801'),
        (x '43e158e460913cff'),
        (x '43e158e460913d00'),
        (x '43e158e460913d01'),
        (x '4415af1d78b58c3f'),
        (x '4415af1d78b58c40'),
        (x '4415af1d78b58c41'),
        (x '444b1ae4d6e2ef4f'),
        (x '444b1ae4d6e2ef50'),
        (x '444b1ae4d6e2ef51'),
        (x '4480f0cf064dd591'),
        (x '4480f0cf064dd592'),
        (x '4480f0cf064dd593'),
        (x '44b52d02c7e14af5'),
        (x '44b52d02c7e14af6'),
        (x '44b52d02c7e14af7'),
        (x '44ea784379d99db3'),
        (x '44ea784379d99db4'),
        (x '44ea784379d99db5'),
        (x '45208b2a2c280290'),
        (x '45208b2a2c280291'),
        (x '45208b2a2c280292'),
        --
        (x '7feffffffffffffe'),
        (x '7fefffffffffffff'),
        -- round to even tests (+ve)
        (x '4350000000000002'),
        (x '4350000000002e06'),
        (x '4352000000000003'),
        (x '4352000000000004'),
        (x '4358000000000003'),
        (x '4358000000000004'),
        (x '435f000000000020'),
        -- round to even tests (-ve)
        (x 'c350000000000002'),
        (x 'c350000000002e06'),
        (x 'c352000000000003'),
        (x 'c352000000000004'),
        (x 'c358000000000003'),
        (x 'c358000000000004'),
        (x 'c35f000000000020'),
        -- exercise fixed-point memmoves
        (x '42dc12218377de66'),
        (x '42a674e79c5fe51f'),
        (x '4271f71fb04cb74c'),
        (x '423cbe991a145879'),
        (x '4206fee0e1a9e061'),
        (x '41d26580b487e6b4'),
        (x '419d6f34540ca453'),
        (x '41678c29dcd6e9dc'),
        (x '4132d687e3df217d'),
        (x '40fe240c9fcb68c8'),
        (x '40c81cd6e63c53d3'),
        (x '40934a4584fd0fdc'),
        (x '405edd3c07fb4c93'),
        (x '4028b0fcd32f7076'),
        (x '3ff3c0ca428c59f8'),
        -- these cases come from the upstream's testsuite
        -- LotsOfTrailingZeros)
        (x '3e60000000000000'),
        -- Regression
        (x 'c352bd2668e077c4'),
        (x '434018601510c000'),
        (x '43d055dc36f24000'),
        (x '43e052961c6f8000'),
        (x '3ff3c0ca2a5b1d5d'),
        -- LooksLikePow5
        (x '4830f0cf064dd592'),
        (x '4840f0cf064dd592'),
        (x '4850f0cf064dd592'),
        -- OutputLength
        (x '3ff3333333333333'),
        (x '3ff3ae147ae147ae'),
        (x '3ff3be76c8b43958'),
        (x '3ff3c083126e978d'),
        (x '3ff3c0c1fc8f3238'),
        (x '3ff3c0c9539b8887'),
        (x '3ff3c0ca2a5b1d5d'),
        (x '3ff3c0ca4283de1b'),
        (x '3ff3c0ca43db770a'),
        (x '3ff3c0ca428abd53'),
        (x '3ff3c0ca428c1d2b'),
        (x '3ff3c0ca428c51f2'),
        (x '3ff3c0ca428c58fc'),
        (x '3ff3c0ca428c59dd'),
        (x '3ff3c0ca428c59f8'),
        (x '3ff3c0ca428c59fb'),
        -- 32-bit chunking
        (x '40112e0be8047a7d'),
        (x '40112e0be815a889'),
        (x '40112e0be826d695'),
        (x '40112e0be83804a1'),
        (x '40112e0be84932ad'),
        -- MinMaxShift
        (x '0040000000000000'),
        (x '007fffffffffffff'),
        (x '0290000000000000'),
        (x '029fffffffffffff'),
        (x '4350000000000000'),
        (x '435fffffffffffff'),
        (x '1330000000000000'),
        (x '133fffffffffffff'),
        (x '3a6fa7161a4d6e0c'))
SELECT
    float8send(flt) AS ibits,
    flt,
    flt::text::float8 AS r_flt,
    float8send(flt::text::float8) AS obits,
    float8send(flt::text::float8) = float8send(flt) AS correct
FROM (
    SELECT
        bits::bigint::xfloat8::float8 AS flt
    FROM
        testdata offset 0) s;

-- clean up, lest opr_sanity complain
DROP TYPE xfloat8 CASCADE;

