Numeric functions and operators

Numeric constants

Function HTSQL SQL Javascript Python
The Pi constant pi() pi() Math.PI math.pi
The E constant e() exp(1.0) Math.E math.e
The numeric NaN value nan() ??? NUMERIC 'NaN' -- --
The float Infinity value infinity() ??? DOUBLE PRECISION 'Infinity' Infinity --
The float -Infinity value -infinity() (doesn't really work) DOUBLE PRECISION '-Infinity' -Infinity --
The float NaN value nan() (difference between float and numeric?) DOUBLE PRECISION 'NaN' NaN --

Signatures:

  • htsql:pi() -> Number
  • htsql:e() -> Number
  • ???

PostgreSQL supports NaN, Infinity and -Infinity float values. However there seems no mean to check for these values. There's also a NUMERIC NaN value.

PostgreSQL produces the error value out of range: overflow for the expression (- DOUBLE PRECISION 'Infinity') so it could not be used for producing the (DOUBLE PRECISION '-Infinity') value.

On the other hand, the following expression are true:

  • NUMERIC 'NaN' = NUMERIC 'NaN'
  • DOUBLE PRECISION 'NaN' = DOUBLE PRECISION 'NaN'
  • DOUBLE PRECISION 'Infinity' = DOUBLE PRECISION 'Infinity'
  • DOUBLE PRECISION '-Infinity' = DOUBLE PRECISION '-Infinity'
  • DOUBLE PRECISION 'NaN' > DOUBLE PRECISION 'Infinity'
  • DOUBLE PRECISION 'Infinity' > DOUBLE PRECISION '-Infinity'

It's not clear if adding NaN, Infinity, and -Infinity constants will add any value to HTSQL?

Supporting special IEEE 754 values is a tough problem. It is better to drop them totally if we cannot support them properly.

Numeric cast

Function HTSQL SQL Javascript Python
Cast to Number number(value) CAST(value AS NUMERIC) Number(value) int(value); float(value)
Cast to Integer integer(value) CAST(value AS INTEGER) -- int(value)

Signatures:

  • htsql:number(Number value) -> Number
  • htsql:number(String value) -> Number
  • htsql:integer(Number value) -> Number(scale=0)
  • htsql:integer(String value) -> Number(scale=0)
  • htsql:integer(Boolean value) -> Number(scale=0)

Type resolution: htsql:number(Untyped => Number), htsql:integer(Untyped => Number).

If the argument of the function htsql:number() is a Number, it is no-op. A String argument is converted to a number using the SQL CAST(... AS NUMERIC) operator.

FIXME: htsql:number(Boolean | BitString | TimeInterval value) -> Number ???

A possible alternative form:

  • htsql.number(Number | String value[, Number precision[, Number scale]]) -> Number

The expression number(value, precision, scale) is converted to the SQL expression CAST(value AS NUMERIC(precision, scale)). Therefore the parameters precision and scale must be literal values. The question is: do we really need this form?

Arithmetic operators

Function HTSQL SQL Javascript Python
Unary + (no-op) +x + x + x + x
Unary - (negation) -x - x - x - x
Binary + (addition) x+y x + y x + y x + y
Binary - (substraction) x-y x - y x - y x - y
Binary * (multiplication) x*y x * y x * y x * y
Binary / (division) x div y x / y x / y x / y; x // y
Binary % (remainder) x mod y x % y x % y x % y
Binary ^ (power) x ^ y x ^ y Math.pow(x, y) x ** y

Signatures:

  • htsql:operator:"+()"(Number x) -> Number
  • htsql:operator:"-()"(Number x) -> Number
  • htsql:operator:"+"(Number x, Number y) -> Number
  • htsql:operator:"-"(Number x, Number y) -> Number
  • htsql:operator:"*"(Number x, Number y) -> Number
  • htsql:operator:"div"(Number x, Number y) -> Number
  • htsql:operator:"mod"(Number x, Number y) -> Number
  • htsql:operator:"^"(Number x, Number y) -> Number

Type resolution:

  • htsql:operator:"+()"(Untyped => Number)
  • htsql:operator:"-()"(Untyped => Number)
  • htsql:operator:"+"(Untyped => Number, Number), htsql:operator:"+"(Number, Untyped => Number)
  • htsql:operator:"-"(Untyped => Number, Number), htsql:operator:"-"(Number, Untyped => Number)
  • htsql:operator:"*"(Untyped => Number, Number), htsql:operator:"*"(Number, Untyped => Number)
  • htsql:operator:"div"(Untyped => Number, Untyped => Number)
  • htsql:operator:"mod"(Untyped => Number, Untyped => Number)
  • htsql:operator:"^"(Untyped => Number, Untyped => Number)

Notice: integer division truncates results.

Bitwise operations

Function HTSQL SQL Javascript Python
Bitwise AND bitwise_and(x,y) x & y x & y x & y
Bitwise OR bitwise_or(x,y) x | y x | y x | y
Bitwise XOR bitwise_xor(x,y) x # y x ^ y x ^ y
Bitwise NOT bitwise_not(x) ~ x ~ x ~ x
Bitwise shift left bitwise_lshift(x,y) x << y x << y x << y
Bitwise shift right bitwise_rshift(x,y) x >> y x >> y x >> y

Signatures:

  • htsql:bitwise_and(Number(is_integer=True) x, Number(is_integer=True) y) -> Number(is_integer=True)
  • htsql:bitwise_or(Number(is_integer=True) x, Number(is_integer=True) y) -> Number(is_integer=True)
  • htsql:bitwise_xor(Number(is_integer=True) x, Number(is_integer=True) y) -> Number(is_integer=True)
  • htsql:bitwise_not(Number(is_integer=True) x) -> Number(is_integer=True)
  • htsql:bitwise_lshift(Number(is_integer=True) x, Number(is_integer=True) y) -> Number(is_integer=True)
  • htsql:bitwise_rshift(Number(is_integer=True) x, Number(is_integer=True) y) -> Number(is_integer=True)

Type resolution: Untyped => Number for all arguments

Mathematical functions

Function HTSQL SQL Javascript Python
Absolute value of the argument abs(x) abs(x) Math.abs(x) abs(x)
Sign of the argument sign(x) sign(x) -- --
Ceiling (smallest integer >= argument) ceil(x) ceil(x) Math.ceil(x) math.ceil(x)
Floor (largest integer <= argument) floor(x) floor(x) Math.floor(x) math.floor(x)
Truncate toward zero trunc(x[,n=0]) trunc(x[, n]) -- --
Round to nearest integer round(x[,n=0]) round(x[, n]) -- round(x[, n=0])
Square root sqrt(x) sqrt(x) Math.sqrt(x) math.sqrt(x)
Cube root cbrt(x) (?) cbrt(x) -- --
Exponential exp(x) exp(x) Math.exp(x) math.exp(x)
Natural logarithm ln(x) ln(x) Math.log(x) math.log(x)
Base 10 logarithm log10(x) log(x) -- math.log10(x)
Logarithm log(x,b) log(x, b) -- math.log(x, b)
Radians to degrees degrees(x) degress(x) -- degrees(x)
Degrees to radians radians(x) radians(x) -- radians(x)
Set seed for random() calls setseed(x) (?) setseed(x) -- random.seed([x])
Random value between 0.0 and 1.0 random() random() Math.random() random.random()

Signatures:

  • htsql:abs(Number x) -> Number
  • htsql:sign(Number x) -> Number
  • htsql:ceil(Number x) -> Number
  • htsql:floor(Number x) -> Number
  • htsql:trunc(Number x[, Number(is_integer=True) n]) -> Number
  • htsql:round(Number x[, Number(is_integer=True) n]) -> Number
  • htsql:sqrt(Number x) -> Number
  • htsql:cbrt(Number x) -> Number
  • htsql:exp(Number x) -> Number
  • htsql:ln(Number x) -> Number
  • htsql:log10(Number x) -> Number
  • htsql:log(Number x, Number b) -> Number
  • htsql:degrees(Number x) -> Number
  • htsql:radians(Number x) -> Number
  • htsql:setseed(Number x) -> Number
  • htsql:random() -> Number

Type resolution: Untyped => Number for all arguments

Notes:

  • The default base for the function log() is 10 in SQL and 2 in Python. So we would better not allow using log() without the explicit base.
  • The function cbrt() should be dropped. Could be easily replaced with x ^ (1.0/3.0).
  • The function setseed() should be dropped or, at least, renamed.

Trigonometric functions

Function HTSQL SQL Javascript Python
Sine sin(t) sin(t) Math.sin(t) math.sin(t)
Cosine cos(t) cos(t) Math.cos(t) math.cos(t)
Tangent tan(t) tan(t) Math.tan(t) math.tan(t)
Cotangent cot(t) cot(t) -- --
Inverse sine asin(t) asin(t) Math.asin(t) math.asin(t)
Inverse cosine acos(t) acos(t) Math.acos(t) math.acos(t)
Inverse tangent atan(t) atan(t) Math.atan(t) math.atan(t)
Inverse tangent of y/x atan2(y,x) atan2(y, x) Math.atan2(y, x) math.atan2(y, x)

Signatures:

  • htsql:sin(Number t) -> Number
  • htsql:cos(Number t) -> Number
  • htsql:tan(Number t) -> Number
  • htsql:cot(Number t) -> Number
  • htsql:asin(Number t) -> Number
  • htsql:acos(Number t) -> Number
  • htsql:atan(Number t) -> Number
  • htsql:atan2(Number y, Number x) -> Number

Type resolution: Untyped => Number for all arguments