--
-- 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;

