mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 23:21:59 +00:00
Add test for accurate numbers comparisons. [#CLICKHOUSE-194]
This commit is contained in:
parent
7d86246b46
commit
3e53e3268a
@ -44,16 +44,16 @@ namespace DB
|
||||
* TODO Массивы.
|
||||
*/
|
||||
|
||||
template <typename A, typename B> struct EqualsOp { static UInt8 apply(A a, B b) { return accurate::equalsOp<A, B>(a, b); } };
|
||||
template <typename A, typename B> struct NotEqualsOp { static UInt8 apply(A a, B b) { return accurate::notEqualsOp<A, B>(a, b); } };
|
||||
template <typename A, typename B> struct LessOp { static UInt8 apply(A a, B b) { return accurate::lessOp<A, B>(a, b); } };
|
||||
template <typename A, typename B> struct GreaterOp { static UInt8 apply(A a, B b) { return accurate::greaterOp<A, B>(a, b); } };
|
||||
template <typename A, typename B> struct LessOrEqualsOp { static UInt8 apply(A a, B b) { return accurate::lessOrEqualsOp<A, B>(a, b); } };
|
||||
template <typename A, typename B> struct GreaterOrEqualsOp { static UInt8 apply(A a, B b) { return accurate::greaterOrEqualsOp<A, B>(a, b); } };
|
||||
template <typename A, typename B> struct EqualsOp { static UInt8 apply(A a, B b) { return accurate::equalsOp(a, b); } };
|
||||
template <typename A, typename B> struct NotEqualsOp { static UInt8 apply(A a, B b) { return accurate::notEqualsOp(a, b); } };
|
||||
template <typename A, typename B> struct LessOp { static UInt8 apply(A a, B b) { return accurate::lessOp(a, b); } };
|
||||
template <typename A, typename B> struct GreaterOp { static UInt8 apply(A a, B b) { return accurate::greaterOp(a, b); } };
|
||||
template <typename A, typename B> struct LessOrEqualsOp { static UInt8 apply(A a, B b) { return accurate::lessOrEqualsOp(a, b); } };
|
||||
template <typename A, typename B> struct GreaterOrEqualsOp { static UInt8 apply(A a, B b) { return accurate::greaterOrEqualsOp(a, b); } };
|
||||
|
||||
/** Игнорируем warning о сравнении signed и unsigned.
|
||||
* (Результат может быть некорректным.)
|
||||
*/
|
||||
// /** Игнорируем warning о сравнении signed и unsigned.
|
||||
// * (Результат может быть некорректным.)
|
||||
// */
|
||||
// #pragma GCC diagnostic push
|
||||
// #pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
//
|
||||
|
25
dbms/tests/perf_drafts/accurate_comparisons/accurate_comparisons.sh
Executable file
25
dbms/tests/perf_drafts/accurate_comparisons/accurate_comparisons.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
clickhouse-client -q "DROP TABLE IF EXISTS test.comparisons"
|
||||
clickhouse-client -q "CREATE TABLE test.comparisons (i64 Int64, u64 UInt64, f64 Float64) ENGINE = Memory"
|
||||
clickhouse-client -q "INSERT INTO test.comparisons SELECT toInt64(rand64()) + number AS i64, number AS u64, reinterpretAsFloat64(reinterpretAsString(rand64())) AS f64 FROM system.numbers LIMIT 90000000"
|
||||
|
||||
function test_cmp {
|
||||
echo -n "$1 : "
|
||||
echo -n $(clickhouse-client --max_threads=1 --time -q "SELECT sum(ignore($i)) FROM test.comparisons" 1>/dev/null)
|
||||
}
|
||||
|
||||
test_cmp "u64 = i64"
|
||||
test_cmp "u64 >= i64"
|
||||
|
||||
test_cmp "i64 > -1 "
|
||||
test_cmp "i64 = 0 "
|
||||
test_cmp "u64 != 0 "
|
||||
|
||||
test_cmp "i64 = f64"
|
||||
test_cmp "i64 < f64"
|
||||
|
||||
test_cmp "f64 >= 0 "
|
||||
|
||||
clickhouse-client -q "DROP TABLE IF EXISTS test.comparisons"
|
@ -0,0 +1 @@
|
||||
PASSED
|
143
dbms/tests/queries/0_stateless/00411_accurate_number_comparison.sh
Executable file
143
dbms/tests/queries/0_stateless/00411_accurate_number_comparison.sh
Executable file
@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
import os, itertools, urllib
|
||||
|
||||
def get_ch_answer(query):
|
||||
return urllib.urlopen('http://127.0.0.1:8123', data=query).read()
|
||||
|
||||
def check_answers(query, answer):
|
||||
ch_answer = get_ch_answer(query)
|
||||
if ch_answer.strip() != answer.strip():
|
||||
print("FAIL on query:", query)
|
||||
print("Expected answer:", answer)
|
||||
print("Fetched answer :", ch_answer)
|
||||
exit(-1)
|
||||
|
||||
def get_values():
|
||||
values = [0, 1, -1]
|
||||
for bits in [8, 16, 32, 64]:
|
||||
values += [2**bits, 2**bits - 1]
|
||||
values += [2**(bits-1) - 1, 2**(bits-1), 2**(bits-1) + 1]
|
||||
values += [-2**(bits-1) - 1, -2**(bits-1), -2**(bits-1) + 1]
|
||||
return values
|
||||
|
||||
def is_valid_integer(x):
|
||||
return -2**63 <= x and x <= 2**64-1
|
||||
|
||||
|
||||
TEST_WITH_CASTING=True
|
||||
GENERATE_TEST_FILES=False
|
||||
|
||||
TYPES = {
|
||||
"UInt8" : { "bits" : 8, "sign" : False, "float" : False },
|
||||
"Int8" : { "bits" : 8, "sign" : True, "float" : False },
|
||||
|
||||
"UInt16": { "bits" : 16, "sign" : False, "float" : False },
|
||||
"Int16" : { "bits" : 16, "sign" : True, "float" : False },
|
||||
|
||||
"UInt32": { "bits" : 32, "sign" : False, "float" : False },
|
||||
"Int32" : { "bits" : 32, "sign" : True, "float" : False },
|
||||
|
||||
"UInt64": { "bits" : 64, "sign" : False, "float" : False },
|
||||
"Int64" : { "bits" : 64, "sign" : True, "float" : False }
|
||||
|
||||
#"Float32" : { "bits" : 32, "sign" : True, "float" : True },
|
||||
#"Float64" : { "bits" : 64, "sign" : True, "float" : True }
|
||||
}
|
||||
|
||||
|
||||
def inside_range(value, type_name):
|
||||
bits = TYPES[type_name]["bits"]
|
||||
signed = TYPES[type_name]["sign"]
|
||||
is_float = TYPES[type_name]["float"]
|
||||
|
||||
if is_float:
|
||||
return True
|
||||
|
||||
if signed:
|
||||
return -2**(bits-1) <= value and value <= 2**(bits-1) - 1
|
||||
else:
|
||||
return 0 <= value and value <= 2**bits - 1
|
||||
|
||||
|
||||
def test_operators(v1, v2, v1_passed, v2_passed):
|
||||
query_str = "{v1} = {v2}, {v1} != {v2}, {v1} < {v2}, {v1} <= {v2}, {v1} > {v2}, {v1} >= {v2},\t".format(v1=v1_passed, v2=v2_passed)
|
||||
query_str += "{v1} = {v2}, {v1} != {v2}, {v1} < {v2}, {v1} <= {v2}, {v1} > {v2}, {v1} >= {v2} ".format(v1=v2_passed, v2=v1_passed)
|
||||
|
||||
answers = [v1 == v2, v1 != v2, v1 < v2, v1 <= v2, v1 > v2, v1 >= v2]
|
||||
answers += [v2 == v1, v2 != v1, v2 < v1, v2 <= v1, v2 > v1, v2 >= v1]
|
||||
|
||||
answers_str = "\t".join([str(int(x)) for x in answers])
|
||||
|
||||
return (query_str, answers_str)
|
||||
|
||||
|
||||
VALUES = [x for x in get_values() if is_valid_integer(x)]
|
||||
|
||||
def test_pair(v1, v2):
|
||||
query = "SELECT {}, {}, ".format(v1, v2)
|
||||
answers = "{}\t{}\t".format(v1, v2)
|
||||
|
||||
q, a = test_operators(v1, v2, str(v1), str(v2))
|
||||
query += q
|
||||
answers += a
|
||||
|
||||
if TEST_WITH_CASTING:
|
||||
for t1 in TYPES.iterkeys():
|
||||
if inside_range(v1, t1):
|
||||
for t2 in TYPES.iterkeys():
|
||||
if inside_range(v2, t2):
|
||||
q, a = test_operators(v1, v2, 'to{}({})'.format(t1, v1), 'to{}({})'.format(t2, v2))
|
||||
query += ', ' + q
|
||||
answers += "\t" + a
|
||||
|
||||
check_answers(query, answers)
|
||||
return query, answers
|
||||
|
||||
|
||||
VALUES_INT = [0, -1, 1, 2**64-1, 2**63, -2**63, 2**63-1, 2**51, 2**52, 2**53-1, 2**53, 2**53+1, 2**53+2, -2**53+1, -2**53, -2**53-1, -2**53-2, 2*52, -2**52]
|
||||
VALUES_FLOAT = [float(x) for x in VALUES_INT + [-0.5, 0.5, -1.5, 1.5, 2**53, 2**51 - 0.5, 2**51 + 0.5, 2**60, -2**60, -2**63 - 10000, 2**63 + 10000]]
|
||||
|
||||
def test_float_pair(i, f):
|
||||
f_str = ("%.9f" % f)
|
||||
query = "SELECT '{}', '{}', ".format(i, f_str)
|
||||
answers = "{}\t{}\t".format(i, f_str)
|
||||
|
||||
q, a = test_operators(i, f, i, f_str)
|
||||
query += q
|
||||
answers += a
|
||||
|
||||
if TEST_WITH_CASTING:
|
||||
for t1 in TYPES.iterkeys():
|
||||
if inside_range(i, t1):
|
||||
q, a = test_operators(i, f, 'to{}({})'.format(t1, i), f_str)
|
||||
query += ', ' + q
|
||||
answers += "\t" + a
|
||||
|
||||
check_answers(query, answers)
|
||||
return query, answers
|
||||
|
||||
|
||||
def main():
|
||||
if GENERATE_TEST_FILES:
|
||||
base_name = '00411_accurate_number_comparison'
|
||||
sql_file = open(base_name + '.sql', 'wt')
|
||||
ref_file = open(base_name + '.reference', 'wt')
|
||||
|
||||
for (v1, v2) in itertools.combinations(VALUES, 2):
|
||||
q, a = test_pair(v1, v2)
|
||||
if GENERATE_TEST_FILES:
|
||||
sql_file.write(q + ";\n")
|
||||
ref_file.write(a + "\n")
|
||||
|
||||
for (i, f) in itertools.product(VALUES_INT, VALUES_FLOAT):
|
||||
q, a = test_float_pair(i, f)
|
||||
if GENERATE_TEST_FILES:
|
||||
sql_file.write(q + ";\n")
|
||||
ref_file.write(a + "\n")
|
||||
|
||||
print("PASSED")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user