require "c/stdio" require "c/string" require "./float/printer" # Float is the base type of all floating point numbers. # # There are two floating point types, `Float32` and `Float64`, # which correspond to the [binary32](http://en.wikipedia.org/wiki/Single_precision_floating-point_format) # and [binary64](http://en.wikipedia.org/wiki/Double_precision_floating-point_format) # types defined by IEEE. # # A floating point literal is an optional `+` or `-` sign, followed by # a sequence of numbers or underscores, followed by a dot, # followed by numbers or underscores, followed by an optional exponent suffix, # followed by an optional type suffix. If no suffix is present, the literal's type is `Float64`. # # ``` # 1.0 # Float64 # 1.0_f32 # Float32 # 1_f32 # Float32 # # 1e10 # Float64 # 1.5e10 # Float64 # 1.5e-7 # Float64 # # +1.3 # Float64 # -0.5 # Float64 # ``` # # The underscore `_` before the suffix is optional. # # Underscores can be used to make some numbers more readable: # # ``` # 1_000_000.111_111 # better than 1000000.111111 # ``` # # See [`Float` literals](https://crystal-lang.org/reference/syntax_and_semantics/literals/floats.html) in the language reference. struct Float alias Primitive = Float32 | Float64 # Negates this value's sign. def - # fallback implementation; does not handle IEEE 754 signed zeros correctly self.class.zero - self end def //(other) self.fdiv(other).floor end def %(other) modulo(other) end # Returns whether this value is a not-a-number. # # This includes both quiet and signalling NaNs from IEEE 754. def nan? : Bool !(self == self) end # Checks whether this value is infinite. Returns `1` if this value is positive # infinity, `-1` if this value is negative infinity, or `nil` otherwise. def infinite? : Int32? # fallback implementation # TODO: consider using https://llvm.org/docs/LangRef.html#llvm-is-fpclass-intrinsic if nan? || self == 0 || self != 2 * self nil else self > 0 ? 1 : -1 end end # Returns whether this value is finite, i.e. it is neither infinite nor a # not-a-number. def finite? : Bool !nan? && !infinite? end def modulo(other) if other == 0.0 raise DivisionByZeroError.new else self - other * (self // other) end end def remainder(other) if other == 0.0 raise DivisionByZeroError.new else mod = self % other return self.class.zero if mod == 0.0 return mod if self > 0 && other > 0 return mod if self < 0 && other < 0 mod - other end end # Writes this float to the given *io* in the given *format*. # See also: `IO#write_bytes`. def to_io(io : IO, format : IO::ByteFormat) : Nil format.encode(self, io) end # Reads a float from the given *io* in the given *format*. # See also: `IO#read_bytes`. def self.from_io(io : IO, format : IO::ByteFormat) : self format.decode(self, io) end end struct Float32 NAN = (0_f32 / 0_f32).as Float32 INFINITY = (1_f32 / 0_f32).as Float32 # Smallest finite value MIN = -3.40282347e+38_f32 # Largest finite value MAX = 3.40282347e+38_f32 # The machine epsilon (difference between 1.0 and the next representable value) EPSILON = 1.19209290e-07_f32 # The number of decimal digits that can be represented without losing precision DIGITS = 6 # The radix or integer base used by the internal representation RADIX = 2 # The number of digits that can be represented without losing precision (in base RADIX) MANT_DIGITS = 24 # The minimum possible normal power of 2 exponent MIN_EXP = -125 # The maximum possible normal power of 2 exponent MAX_EXP = 128 # The minimum possible power of 10 exponent (such that 10**MIN_10_EXP is representable) MIN_10_EXP = -37 # The maximum possible power of 10 exponent (such that 10**MAX_10_EXP is representable) MAX_10_EXP = 38 # Smallest normal positive value, whose previous representable value is subnormal MIN_POSITIVE = 1.17549435e-38_f32 # Smallest representable positive value, whose previous representable value is zero MIN_SUBNORMAL = 1.0e-45_f32 # Returns a `Float32` by invoking `String#to_f32` on *value*. # # ``` # Float32.new "20" # => 20.0 # Float32.new " 20 ", whitespace: false # raises ArgumentError: Invalid Float32: " 20 " # ``` def self.new(value : String, whitespace : Bool = true, strict : Bool = true) : self value.to_f32 whitespace: whitespace, strict: strict end # Returns a `Float32` by invoking `to_f32` on *value*. def self.new(value) value.to_f32 end # Returns a `Float32` by invoking `to_f32!` on *value*. def self.new!(value) : self value.to_f32! end # Returns a `Float32` by parsing *str* as a hexadecimal-significand string, or # `nil` if parsing fails. # # The string format is defined in section 5.12.3 of IEEE 754-2008, and is the # same as the `%a` specifier for `sprintf`. Unlike e.g. `String#to_f`, # whitespace and underscores are not allowed. Non-finite values are also # recognized. # # ``` # Float32.parse_hexfloat?("0x123.456p7") # => 37282.6875_f32 # Float32.parse_hexfloat?("0x1.fffffep+127") # => Float32::MAX # Float32.parse_hexfloat?("-inf") # => -Float32::INFINITY # Float32.parse_hexfloat?("0x1") # => nil # Float32.parse_hexfloat?("a.bp+3") # => nil # ``` def self.parse_hexfloat?(str : String) : self? Float::Printer::Hexfloat(self, UInt32).to_f(str) { nil } end # Returns a `Float32` by parsing *str* as a hexadecimal-significand string. # # The string format is defined in section 5.12.3 of IEEE 754-2008, and is the # same as the `%a` specifier for `sprintf`. Unlike e.g. `String#to_f`, # whitespace and underscores are not allowed. Non-finite values are also # recognized. # # Raises `ArgumentError` if *str* is not a valid hexadecimal-significand # string. # # ``` # Float32.parse_hexfloat("0x123.456p7") # => 37282.6875_f32 # Float32.parse_hexfloat("0x1.fffffep+127") # => Float32::MAX # Float32.parse_hexfloat("-inf") # => -Float32::INFINITY # Float32.parse_hexfloat("0x1") # Invalid hexfloat: expected 'p' or 'P' (ArgumentError) # Float32.parse_hexfloat("a.bp+3") # Invalid hexfloat: expected '0' (ArgumentError) # ``` def self.parse_hexfloat(str : String) : self Float::Printer::Hexfloat(self, UInt32).to_f(str) do |err| raise ArgumentError.new("Invalid hexfloat: #{err}") end end Number.expand_div [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128], Float32 Number.expand_div [Float64], Float64 # :inherit: def infinite? : Int32? # TODO: consider using https://llvm.org/docs/LangRef.html#llvm-is-fpclass-intrinsic case self when -Float32::INFINITY -1 when Float32::INFINITY 1 end end # Negates this value's sign. # # Works on signed zeros and not-a-number values as well. The negation of # `0.0_f32` is `-0.0_f32`, and vice versa. The negation of a not-a-number # value is only observable via `#sign_bit`. def - : Float32 # equivalent to `Math.copysign(self, -sign_bit.to_f32)` # TODO: consider using the LLVM `fneg` instruction (unsafe_as(UInt32) ^ 0x80000000_u32).unsafe_as(Float32) end def abs : Float32 Math.copysign(self, 1.0_f32) end # Returns `-1` if the sign bit of this float is set, `1` otherwise. # # Unlike `#sign`, this works on signed zeros and not-a-numbers as well. def sign_bit : Int32 Math.copysign(1_f32, self).to_i end # Rounds towards positive infinity. def ceil : Float32 LibM.ceil_f32(self) end # Rounds towards negative infinity. def floor : Float32 LibM.floor_f32(self) end # Rounds towards the nearest integer. If both neighboring integers are equidistant, # rounds towards the even neighbor (Banker's rounding). def round_even : Float32 # TODO: LLVM 11 introduced llvm.roundeven.* intrinsics which may replace # rint in the future. LibM.rint_f32(self) end # Rounds towards the nearest integer. If both neighboring integers are equidistant, # rounds away from zero. def round_away : Float32 LibM.round_f32(self) end # Rounds towards zero. def trunc : Float32 LibM.trunc_f32(self) end # Returns the least `Float32` that is greater than `self`. def next_float : Float32 LibM.nextafter_f32(self, INFINITY) end # Returns the greatest `Float32` that is less than `self`. def prev_float : Float32 LibM.nextafter_f32(self, -INFINITY) end def **(other : Int32) {% if flag?(:win32) %} self ** other.to_f32 {% else %} LibM.powi_f32(self, other) {% end %} end def **(other : Float32) : Float32 LibM.pow_f32(self, other) end def **(other) : Float32 self ** other.to_f32 end def to_s : String String.build(22) do |buffer| Printer.shortest(self, buffer) end end def to_s(io : IO) : Nil Printer.shortest(self, io) end # Returns the hexadecimal-significand representation of `self`. # # The string format is defined in section 5.12.3 of IEEE 754-2008, and is the # same as the `%a` specifier for `sprintf`. The integral part of the returned # string is `0` if `self` is subnormal, otherwise `1`. The fractional part # contains only significant digits. # # ``` # 1234.0625_f32.to_hexfloat # => "0x1.3484p+10" # Float32::MAX.to_hexfloat # => "0x1.fffffep+127" # Float32::MIN_SUBNORMAL.to_hexfloat # => "0x0.000002p-126" # ``` def to_hexfloat : String # the longest `Float64` strings are of the form `-0x1.234567p-127` String.build(16) do |buffer| Printer.hexfloat(self, buffer) end end # Writes `self`'s hexadecimal-significand representation to the given *io*. def to_hexfloat(io : IO) : Nil Printer.hexfloat(self, io) end def clone self end end struct Float64 NAN = (0_f64 / 0_f64).as Float64 INFINITY = (1_f64 / 0_f64).as Float64 # Smallest finite value MIN = -1.7976931348623157e+308_f64 # Largest finite value MAX = 1.7976931348623157e+308_f64 # The machine epsilon (difference between 1.0 and the next representable value) EPSILON = 2.2204460492503131e-16_f64 # The number of decimal digits that can be represented without losing precision DIGITS = 15 # The radix or integer base used by the internal representation RADIX = 2 # The number of digits that can be represented without losing precision (in base RADIX) MANT_DIGITS = 53 # The minimum possible normal power of 2 exponent MIN_EXP = -1021 # The maximum possible normal power of 2 exponent MAX_EXP = 1024 # The minimum possible power of 10 exponent (such that 10**MIN_10_EXP is representable) MIN_10_EXP = -307 # The maximum possible power of 10 exponent (such that 10**MAX_10_EXP is representable) MAX_10_EXP = 308 # Smallest normal positive value, whose previous representable value is subnormal MIN_POSITIVE = 2.2250738585072014e-308_f64 # Smallest representable positive value, whose previous representable value is zero MIN_SUBNORMAL = 5.0e-324_f64 # Returns a `Float64` by invoking `String#to_f64` on *value*. # # ``` # Float64.new "20" # => 20.0 # Float64.new " 20 ", whitespace: false # raises ArgumentError: Invalid Float64: " 20 " # ``` def self.new(value : String, whitespace : Bool = true, strict : Bool = true) : self value.to_f64 whitespace: whitespace, strict: strict end # Returns a `Float64` by invoking `to_f64` on *value*. def Float64.new(value) value.to_f64 end # Returns a `Float64` by invoking `to_f64!` on *value*. def Float64.new!(value) : Float64 value.to_f64! end # Returns a `Float32` by parsing *str* as a hexadecimal-significand string, or # `nil` if parsing fails. # # The string format is defined in section 5.12.3 of IEEE 754-2008, and is the # same as the `%a` specifier for `sprintf`. Unlike e.g. `String#to_f`, # whitespace and underscores are not allowed. Non-finite values are also # recognized. # # ``` # Float64.parse_hexfloat?("0x123.456p7") # => 37282.6875 # Float64.parse_hexfloat?("0x1.fffffep+127") # => Float64::MAX # Float64.parse_hexfloat?("-inf") # => -Float64::INFINITY # Float64.parse_hexfloat?("0x1") # => nil # Float64.parse_hexfloat?("a.bp+3") # => nil # ``` def self.parse_hexfloat?(str : String) : self? Float::Printer::Hexfloat(self, UInt64).to_f(str) { nil } end # Returns a `Float32` by parsing *str* as a hexadecimal-significand string. # # The string format is defined in section 5.12.3 of IEEE 754-2008, and is the # same as the `%a` specifier for `sprintf`. Unlike e.g. `String#to_f`, # whitespace and underscores are not allowed. Non-finite values are also # recognized. # # Raises `ArgumentError` if *str* is not a valid hexadecimal-significand # string. # # ``` # Float64.parse_hexfloat("0x123.456p7") # => 37282.6875 # Float64.parse_hexfloat("0x1.fffffffffffffp+1023") # => Float64::MAX # Float64.parse_hexfloat("-inf") # => -Float64::INFINITY # Float64.parse_hexfloat("0x1") # Invalid hexfloat: expected 'p' or 'P' (ArgumentError) # Float64.parse_hexfloat("a.bp+3") # Invalid hexfloat: expected '0' (ArgumentError) # ``` def self.parse_hexfloat(str : String) : self Float::Printer::Hexfloat(self, UInt64).to_f(str) do |err| raise ArgumentError.new("Invalid hexfloat: #{err}") end end Number.expand_div [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128], Float64 Number.expand_div [Float32], Float64 # :inherit: def infinite? : Int32? # TODO: consider using https://llvm.org/docs/LangRef.html#llvm-is-fpclass-intrinsic case self when -Float64::INFINITY -1 when Float64::INFINITY 1 end end # Negates this value's sign. # # Works on signed zeros and not-a-number values as well. The negation of # `0.0` is `-0.0`, and vice versa. The negation of a not-a-number value is # only observable via `#sign_bit`. def - : Float64 # equivalent to `Math.copysign(self, -sign_bit.to_f64)` # TODO: consider using the LLVM `fneg` instruction (unsafe_as(UInt64) ^ 0x80000000_00000000_u64).unsafe_as(Float64) end def abs : Float64 Math.copysign(self, 1.0) end # Returns `-1` if the sign bit of this float is set, `1` otherwise. # # Unlike `#sign`, this works on signed zeros and not-a-numbers as well. def sign_bit : Int32 Math.copysign(1_f64, self).to_i end def ceil : Float64 LibM.ceil_f64(self) end def floor : Float64 LibM.floor_f64(self) end # Rounds towards the nearest integer. If both neighboring integers are equidistant, # rounds towards the even neighbor (Banker's rounding). def round_even : Float64 # TODO: LLVM 11 introduced llvm.roundeven.* intrinsics which may replace # rint in the future. LibM.rint_f64(self) end # Rounds towards the nearest integer. If both neighboring integers are equidistant, # rounds away from zero. def round_away : Float64 LibM.round_f64(self) end def trunc : Float64 LibM.trunc_f64(self) end # Returns the least `Float64` that is greater than `self`. def next_float : Float64 LibM.nextafter_f64(self, INFINITY) end # Returns the greatest `Float64` that is less than `self`. def prev_float : Float64 LibM.nextafter_f64(self, -INFINITY) end def **(other : Int32) {% if flag?(:win32) %} self ** other.to_f64 {% else %} LibM.powi_f64(self, other) {% end %} end def **(other : Float64) : Float64 LibM.pow_f64(self, other) end def **(other) : Float64 self ** other.to_f64 end def to_s : String # the longest `Float64` strings are of the form `-1.2345678901234567e+123` String.build(24) do |buffer| Printer.shortest(self, buffer) end end def to_s(io : IO) : Nil Printer.shortest(self, io) end # Returns the hexadecimal-significand representation of `self`. # # The string format is defined in section 5.12.3 of IEEE 754-2008, and is the # same as the `%a` specifier for `sprintf`. The integral part of the returned # string is `0` if `self` is subnormal, otherwise `1`. The fractional part # contains only significant digits. # # ``` # 1234.0625.to_hexfloat # => "0x1.3484p+10" # Float64::MAX.to_hexfloat # => "0x1.fffffffffffffp+1023" # Float64::MIN_SUBNORMAL.to_hexfloat # => "0x0.0000000000001p-1022" # ``` def to_hexfloat : String # the longest `Float64` strings are of the form `-0x1.23456789abcdep-1023` String.build(24) do |buffer| Printer.hexfloat(self, buffer) end end # Writes `self`'s hexadecimal-significand representation to the given *io*. def to_hexfloat(io : IO) : Nil Printer.hexfloat(self, io) end def clone self end end