(********************************************************************) (* *) (* float.s7i Floating point support library *) (* Copyright (C) 1993, 1994, 2005, 2008 Thomas Mertes *) (* 2011 - 2016, 2018, 2019 Thomas Mertes *) (* 2021 - 2024 Thomas Mertes *) (* *) (* This file is part of the Seed7 Runtime Library. *) (* *) (* The Seed7 Runtime Library is free software; you can *) (* redistribute it and/or modify it under the terms of the GNU *) (* Lesser General Public License as published by the Free Software *) (* Foundation; either version 2.1 of the License, or (at your *) (* option) any later version. *) (* *) (* The Seed7 Runtime Library is distributed in the hope that it *) (* will be useful, but WITHOUT ANY WARRANTY; without even the *) (* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *) (* PURPOSE. See the GNU Lesser General Public License for more *) (* details. *) (* *) (* You should have received a copy of the GNU Lesser General *) (* Public License along with this program; if not, write to the *) (* Free Software Foundation, Inc., 51 Franklin Street, *) (* Fifth Floor, Boston, MA 02110-1301, USA. *) (* *) (********************************************************************) include "enable_io.s7i"; (** * Double precision floating point numbers. *) const type: float is subtype object; $ system "float" is float; const proc: destroy (ref float: aValue) is action "GEN_DESTR"; const proc: (ref float: dest) ::= (ref float: source) is action "FLT_CREATE"; IN_PARAM_IS_VALUE(float); (** * Default value of ''float'' (0.0). *) const float: (attr float) . value is 0.0; const proc: (inout float: dest) := (in float: source) is action "FLT_CPY"; (** * Plus sign for ''float'' numbers. * @return its operand unchanged. *) const func float: + (in float: number) is action "FLT_PLUS"; (** * Minus sign, negate a ''float'' number. * @return the negated value of the number. *) const func float: - (in float: number) is action "FLT_NEGATE"; (** * Add two ''float'' numbers. * @return the sum of the two numbers. *) const func float: (in float: summand1) + (in float: summand2) is action "FLT_ADD"; (** * Compute the subtraction of two ''float'' numbers. * @return the difference of the two numbers. *) const func float: (in float: minuend) - (in float: subtrahend) is action "FLT_SBTR"; (** * Multiply two ''float'' numbers. * @return the product of the two numbers. *) const func float: (in float: factor1) * (in float: factor2) is action "FLT_MULT"; (** * Compute the division of two ''float'' numbers. * A / 0.0 returns Infinity for A > 0.0 * A / 0.0 returns -Infinity for A < 0.0 * 0.0 / 0.0 returns NaN * @return the quotient of the division. *) const func float: (in float: dividend) / (in float: divisor) is action "FLT_DIV"; (** * Compute the floating-point remainder of a division. * The remainder has the same sign as the dividend. * The remainder is dividend - flt(trunc(dividend / divisor)) * divisor * The remainder is computed without a conversion to integer. * A rem NaN returns NaN * NaN rem B returns NaN * A rem 0.0 returns NaN * Infinity rem B returns NaN * -Infinity rem B returns NaN * 0.0 rem B returns 0.0 for B <> 0.0 * A rem Infinity returns A * @return the floating-point remainder of the division. *) const func float: (in float: dividend) rem (in float: divisor) is action "FLT_REM"; (** * Compute the floating-point modulo of a division. * The modulo has the same sign as the divisor. * The modulo is dividend - floor(dividend / divisor) * divisor * A mod NaN returns NaN * NaN mod B returns NaN * A mod 0.0 returns NaN * Infinity mod B returns NaN * -Infinity mod B returns NaN * 0.0 mod B returns 0.0 for B <> 0.0 * A mod Infinity returns A for A > 0 * A mod Infinity returns Infinity for A < 0 * A mod -Infinity returns A for A < 0 * A mod -Infinity returns -Infinity for A > 0 * @return the floating-point modulo of the division. *) const func float: (in float: dividend) mod (in float: divisor) is action "FLT_MOD"; (** * Compute the exponentiation of a float ''base'' with an [[integer]] ''exponent''. * A ** 0 returns 1.0 * NaN ** 0 returns 1.0 * NaN ** B returns NaN for B <> 0 * 0.0 ** B returns 0.0 for B > 0 * 0.0 ** 0 returns 1.0 * 0.0 ** B returns Infinity for B < 0 * (-0.0) ** B returns -Infinity for B < 0 and odd(B) * A ** B returns 1.0 / A ** (-B) for B < 0 * @return the result of the exponentiation. *) const func float: (in float: base) ** (in integer: exponent) is action "FLT_IPOW"; (** * Compute the exponentiation of a float ''base'' with a float ''exponent''. * A ** B returns NaN for A < 0.0 and B is not integer * A ** 0.0 returns 1.0 * NaN ** 0.0 returns 1.0 * NaN ** B returns NaN for B <> 0.0 * 0.0 ** B returns 0.0 for B > 0.0 * 0.0 ** 0.0 returns 1.0 * 0.0 ** B returns Infinity for B < 0.0 * (-0.0) ** B returns -Infinity for B < 0.0 and odd(B) * 1.0 ** B returns 1.0 * 1.0 ** NaN returns 1.0 * A ** NaN returns NaN for A <> 1.0 * @return the result of the exponentiation. *) const func float: (in float: base) ** (in float: exponent) is action "FLT_POW"; (** * Multiply ''number'' by 2 raised to the power of ''exponent''. * In other words: A << B is equivalent to A * 2.0 ** B * If the result underflows zero is returned. * If the result overflows Infinity or -Infinity is returned, * depending on the sign of ''number''. * If the argument ''number'' is a [[#NaN|NaN]], Infinity or -Infinity the * unchanged argument is returned. * @return number * 2.0 ** exponent *) const func float: (in float: number) << (in integer: exponent) is action "FLT_LSHIFT"; (** * Divide ''number'' by 2 raised to the power of ''exponent''. * In other words: A >> B is equivalent to A / 2.0 ** B * If the result underflows zero is returned. * If the result overflows Infinity or -Infinity is returned, * depending on the sign of ''number''. * If the argument ''number'' is a [[#NaN|NaN]], Infinity or -Infinity the * unchanged argument is returned. * @return number / 2.0 ** exponent *) const func float: (in float: number) >> (in integer: exponent) is action "FLT_RSHIFT"; (** * Increment a float ''number'' by a ''delta''. *) const proc: (inout float: number) +:= (in float: delta) is action "FLT_ADD_ASSIGN"; (** * Decrement a float ''number'' by a ''delta''. *) const proc: (inout float: number) -:= (in float: delta) is action "FLT_SBTR_ASSIGN"; (** * Multiply a float ''number'' by a ''factor'' and assign the result back to ''number''. *) const proc: (inout float: number) *:= (in float: factor) is action "FLT_MULT_ASSIGN"; (** * Divide a float ''number'' by a ''divisor'' and assign the result back to ''number''. *) const proc: (inout float: number) /:= (in float: divisor) is action "FLT_DIV_ASSIGN"; (** * Check if two float numbers are equal. * According to IEEE 754 a [[#NaN|NaN]] is not equal to any float value. * Therefore ''NaN = any_value'' and ''any_value = NaN'' * always return FALSE. Even ''NaN = NaN'' returns FALSE. * @return TRUE if both numbers are equal, FALSE otherwise. *) const func boolean: (in float: number1) = (in float: number2) is action "FLT_EQ"; (** * Check if two float numbers are not equal. * According to IEEE 754 a [[#NaN|NaN]] is not equal to any float value. * Therefore ''NaN <> any_value'' and ''any_value <> NaN'' * always return TRUE. Even ''NaN <> NaN'' returns TRUE. * @return FALSE if both numbers are equal, TRUE otherwise. *) const func boolean: (in float: number1) <> (in float: number2) is action "FLT_NE"; (** * Check if ''number1'' is less than ''number2''. * According to IEEE 754 a [[#NaN|NaN]] is neither less than, * equal to, nor greater than any value, including itself. * If ''number1'' or ''number2'' is NaN, the result * is FALSE; * @return TRUE if ''number1'' is less than ''number2'', * FALSE otherwise. *) const func boolean: (in float: number1) < (in float: number2) is action "FLT_LT"; (** * Check if ''number1'' is greater than ''number2''. * According to IEEE 754 a [[#NaN|NaN]] is neither less than, * equal to, nor greater than any value, including itself. * If ''number1'' or ''number2'' is NaN, the result * is FALSE; * @return TRUE if ''number1'' is greater than ''number2'', * FALSE otherwise. *) const func boolean: (in float: number1) > (in float: number2) is action "FLT_GT"; (** * Check if ''number1'' is less than or equal to ''number2''. * According to IEEE 754 a [[#NaN|NaN]] is neither less than, * equal to, nor greater than any value, including itself. * If ''number1'' or ''number2'' is NaN, the result * is FALSE; * @return TRUE if ''number1'' is less than or equal to ''number2'', * FALSE otherwise. *) const func boolean: (in float: number1) <= (in float: number2) is action "FLT_LE"; (** * Check if ''number1'' is greater than or equal to ''number2''. * According to IEEE 754 a [[#NaN|NaN]] is neither less than, * equal to, nor greater than any value, including itself. * If ''number1'' or ''number2'' is NaN, the result * is FALSE; * @return TRUE if ''number1'' is greater than or equal to ''number2'', * FALSE otherwise. *) const func boolean: (in float: number1) >= (in float: number2) is action "FLT_GE"; (** * Positive infinity. * Infinity is the result of 1.0 / 0.0 . *) const float: Infinity is 1.0 / 0.0; (** * Not-a-Number (NaN) value. * Represents an undefined or unrepresentable value. * NaN is the result of 0.0 / 0.0 . * Checking for NaN is done with the function [[#isNaN(in_float)|isNaN]]. *) const float: NaN is 0.0 / 0.0; (** * Compare two float numbers. * Because ''compare'' is used to sort float values, a unique * sort sequence of the values is needed. Therefore ''compare'' * considers all [[#NaN|NaN]] values as greater than Infinity. * The NaN values are also considered to be equal to each other. * Negative zero (-0.0) is considered by ''compare'' to be * equal to positive zero (+0.0). This conforms to the behavior * of all other float comparisons with zero. * @return -1, 0 or 1 if the first argument is considered to be * respectively less than, equal to, or greater than the * second. *) const func integer: compare (in float: number1, in float: number2) is action "FLT_CMP"; (** * Compute the hash value of a float number. * @return the hash value. *) const func integer: hashCode (in float: number) is action "FLT_HASHCODE"; (** * Convert a float number to a [[string]]. * The number is converted to a string with decimal representation. * The result string has the style [-]ddd.ddd where there is at least * one digit before and after the decimal point. The number of digits * after the decimal point is determined automatically. Except for the * case with only one zero digit after the decimal point the last digit * is never zero. Negative zero (-0.0) and positive zero (+0.0) * are both converted to "0.0". * str(16.125) returns "16.125" * str(-0.0) returns "0.0" * str(Infinity) returns "Infinity" * str(-Infinity) returns "-Infinity" * str(NaN) returns "NaN" * @return the string result of the conversion. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func string: str (in float: number) is action "FLT_STR"; (** * Convert a float number to a [[string]]. * The number is converted to a string with decimal representation. * The result string has the style [-]ddd.ddd where there is at least * one digit before and after the decimal point. The number of digits * after the decimal point is determined automatically. Except for the * case with only one zero digit after the decimal point the last digit * is never zero. Negative zero (-0.0) and positive zero (+0.0) * are both converted to "0.0". * string(16.125) returns "16.125" * string(-0.0) returns "0.0" * string(Infinity) returns "Infinity" * string(-Infinity) returns "-Infinity" * string(NaN) returns "NaN" * @return the string result of the conversion. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func string: string (in float: number) is action "FLT_STR"; (** * Convert a [[string]] to a float number. * float("1.2345") returns 1.2345 * float("1.2345e6") returns 1234500.0 * float("-1.0e-308") returns -1.0e-308 * float("1") returns 1.0 * float("2.") returns 2.0 * float(".5") returns 0.5 * float("-.25") returns -0.25 * float("Infinity") returns Infinity * float("-Infinity") returns -Infinity * float("NaN") returns NaN * float("3.14PI" raises RANGE_ERROR * @return the float result of the conversion. * @exception RANGE_ERROR If the string contains not a float literal. *) const func float: float (in string: stri) is action "FLT_PARSE1"; (** * Convert a [[string]] to a float number. * float parse "1.2345" returns 1.2345 * float parse "1.2345e6" returns 1234500.0 * float parse "-1.0e-308" returns -1.0e-308 * float parse "1" returns 1.0 * float parse "2." returns 2.0 * float parse ".5" returns 0.5 * float parse "-.25" returns -0.25 * float parse "Infinity" returns Infinity * float parse "-Infinity" returns -Infinity * float parse "NaN" returns NaN * float parse "2.14PI" raises RANGE_ERROR * @return the float result of the conversion. * @exception RANGE_ERROR If the string contains not a float literal. *) const func float: (attr float) parse (in string: stri) is return float(stri); (** * Convert a ''float'' to a [[string]] in decimal fixed point notation. * The number is rounded to the specified number of digits (''precision''). * Halfway cases are rounded away from zero. Except for a ''precision'' of * zero the representation has a decimal point and at least one digit * before and after the decimal point. Negative numbers are preceded by * a minus sign (e.g.: "-1.25"). If all digits in the result are 0 a * possible negative sign is omitted. * 0.012345 digits 4 returns "0.0123" * 1.2468 digits 2 returns "1.25" * 3.1415 digits 0 returns "3" * 0.125 digits 2 returns "0.12" * 0.375 digits 2 returns "0.38" * Infinity digits 5 returns "Infinity" * -Infinity digits 6 returns "-Infinity" * NaN digits 7 returns "NaN" * -0.004 digits 2 returns "0.00" * @param precision Number of digits after the decimal point. * If the ''precision'' is zero the decimal point is omitted. * @return the string result of the conversion. * @exception RANGE_ERROR If the ''precision'' is negative. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func string: (in float: number) digits (in integer: precision) is action "FLT_DGTS"; (** * Convert a ''float'' to a [[string]] in scientific notation. * Scientific notation uses a decimal significand and a decimal exponent. * The significand has an optional sign and exactly one digit before the * decimal point. The fractional part of the significand is rounded * to the specified number of digits (''precision''). Halfway cases are * rounded away from zero. The fractional part is followed by the * letter e and an exponent, which is always signed. The value zero is * never written with a negative sign. * 0.012345 sci 4 returns "1.2345e-2" * 1.2468 sci 2 returns "1.25e+0" * 3.1415 sci 0 returns "3e+0" * 0.125 sci 1 returns "1.2e-1" * 0.375 sci 1 returns "3.8e-1" * Infinity sci 5 returns "Infinity" * -Infinity sci 6 returns "-Infinity" * NaN sci 7 returns "NaN" * -0.004 sci 2 returns "-4.00e-3" * -0.0 sci 2 returns "0.00e+0" * @param precision Number of digits after the decimal point. * If the ''precision'' is zero the decimal point is omitted. * @return the string result of the conversion. * @exception RANGE_ERROR If the ''precision'' is negative. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func string: (in float: number) sci (in integer: precision) is action "FLT_SCI"; (** * Set the number of exponent digits in a scientific float notation. * If ''sciNumber'' contains a [[string]] in scientific float notation * the exponent is changed to contain at least ''expDigits'' digits. * If ''sciNumber'' contains not a string in scientific float * notation it is returned unchanged. The ''exp'' operator is * intended to be used together with the ''sci'' operator * 0.012345 sci 4 exp 2 returns "1.2345e-02" * 1.2468e15 sci 2 exp 1 returns "1.25e+15" * 3.1415 sci 0 exp 3 returns "3e+000" * 0.125 sci 1 exp 2 returns "1.2e-01" * 0.375 sci 1 exp 2 returns "3.8e-01" * Infinity sci 5 exp 2 returns "Infinity" * -Infinity sci 6 exp 2 returns "-Infinity" * NaN sci 7 exp 2 returns "NaN" * -0.004 sci 2 exp 2 returns "-4.00e-03" * @return the string result of the conversion. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func string: (in string: sciNumber) exp (in integer: expDigits) is func result var string: paddedStri is ""; local var integer: pos is 0; begin pos := length(sciNumber); while pos >= 1 and sciNumber[pos] >= '0' and sciNumber[pos] <= '9' do decr(pos); end while; if pos >= 2 and sciNumber[pred(pos)] = 'e' and (sciNumber[pos] = '+' or sciNumber[pos] = '-') and expDigits > length(sciNumber) - pos then paddedStri := sciNumber[.. pos] & "0" mult expDigits - length(sciNumber) + pos & sciNumber[succ(pos) ..]; else paddedStri := sciNumber; end if; end func; (** * Convert an [[integer]] to a float. * @return the float result of the conversion. *) const func float: flt (in integer: number) is action "FLT_ICONV1"; (** * Convert an [[integer]] to a float. * @return the float result of the conversion. *) const func float: float (in integer: number) is action "FLT_ICONV1"; (** * Convert an [[integer]] to a float. * @return the float result of the conversion. *) const func float: (attr float) conv (in integer: number) is action "FLT_ICONV3"; (** * Compute the absolute value of a ''float'' number. * @return the absolute value. *) const func float: abs (in float: number) is action "FLT_ABS"; (** * Round a ''float'' to the nearest [[integer]]. * Halfway cases are rounded away from zero. * round( 1.4999) returns 1 * round( 0.5) returns 1 * round( 0.4999) returns 0 * round(-0.4999) returns 0 * round(-0.5) returns -1 * round(-1.4999) returns -1 * round(1.0e+19) raises RANGE_ERROR * @return the rounded value. * @exception RANGE_ERROR If the number is [[#NaN|NaN]], -Infinity, Infinity, * or does not fit into an integer. *) const func integer: round (in float: number) is action "FLT_ROUND"; (** * Truncate towards zero. * The fractional part of a number is discarded. * trunc( 1.9999) returns 1 * trunc( 1.0) returns 1 * trunc( 0.9999) returns 0 * trunc(-0.9999) returns 0 * trunc(-1.0) returns -1 * trunc(-1.9999) returns -1 * trunc(1.0e+19) raises RANGE_ERROR * @return the nearest [[integer]] not larger in absolute value * than the argument. * @exception RANGE_ERROR If the number is [[#NaN|NaN]], -Infinity, Infinity, * or does not fit into an integer. *) const func integer: trunc (in float: number) is action "FLT_TRUNC"; (** * Determine if a number has a Not-a-Number ([[#NaN|NaN]]) value. * NaN represents an undefined or unrepresentable value. * @return TRUE if the number has a Not-a-Number (NaN) value, * FALSE otherwise. *) const func boolean: isNaN (in float: number) is action "FLT_ISNAN"; (** * Determine if a number is negative zero (-0.0). * This function is the only possibility to determine if a number * is -0.0. The comparison operators (=, <>, <, >, <=, >=) and * the function ''compare'' treat 0.0 and -0.0 as equal. The * operators ''digits'' and ''sci'' and the function ''str'' * return the same [[string]] for -0.0 and +0.0. * @return TRUE if the number is -0.0, * FALSE otherwise. *) const func boolean: isNegativeZero (in float: number) is action "FLT_ISNEGATIVEZERO"; (** * Determine if a number is +0.0. * @return TRUE if the number is +0.0, * FALSE otherwise. *) const func boolean: isPositiveZero (in float: number) is return number = 0.0 and not isNegativeZero(number); (** * Convert a float number to a [[string]]. * The number is converted to a string with decimal representation. * @return the string result of the conversion. * @exception MEMORY_ERROR Not enough memory to represent the result. *) const func string: literal (in float: number) is action "FLT_STR"; (** * Compute pseudo-random number in the range [low, high). * The random values are uniform distributed. * @return the computed pseudo-random number. * @exception RANGE_ERROR The range is empty (low >= high holds). *) const func float: rand (in float: low, in float: high) is action "FLT_RAND"; const proc: decompose (in float: number, inout float: fraction, inout integer: exponent) is action "FLT_DECOMPOSE"; const type: floatElements is new struct var float: fraction is 0.0; var integer: exponent is 0; end struct; (** * Decompose float into normalized fraction and integral exponent for 2. * If the argument (number) is 0.0, -0.0, Infinity, -Infinity or [[#NaN|NaN]] * the fraction is set to the argument and the exponent is set to 0. * For all other arguments the fraction is set to an absolute value * between 0.5(included) and 1.0(excluded). For all values of number holds: * number = fraction * 2.0 ** exponent * @param number Number to be decomposed into fraction and exponent. * @return floatElements with fraction and exponent set. *) const func floatElements: decompose (in float: number) is func result var floatElements: elements is floatElements.value; begin decompose(number, elements.fraction, elements.exponent); end func; # Allows 'array float' everywhere without extra type definition. const type: _floatArray is array float; enable_io(float); DECLARE_TERNARY(float); DECLARE_MIN_MAX(float);