Extreme floating point values

From Rosetta Code
Task
Extreme floating point values
You are encouraged to solve this task according to the task description, using any language you may know.

The IEEE floating point specification defines certain 'extreme' floating point values such as minus zero, -0.0, a value distinct from plus zero; not a number, NaN; and plus and minus infinity.

The task is to use expressions involving other 'normal' floating point values in your language to calculate these, (and maybe other), extreme floating point values in your language and assign them to variables. Print the values of these variables if possible; and show some arithmetic with these values and variables. If your language can directly enter these extreme floating point values then show it.


C.f:

Ada

The language specifies model floating-point numbers independent of the underlying hardware. Even if the machine numbers are IEEE 754, the user-defined floating-point numbers are guaranteed to have no IEEE 754 semantics. In particular, their values do not include any non-numeric ideals. Constraint_Error exception is propagated when the result of a numeric operation assigned to a floating-point variable is not in the range (the range is always numeric).

For performance reasons, the built-in floating-point types like Float and Long_Float are allowed to have IEEE 754 semantics if the machine numbers are IEEE 754. But the language provides means to exclude all non numbers from these types by defining a subtype with an explicit range: <lang Ada> subtype Consistent_Float is Float range Float'Range; -- No IEEE ideals </lang> In general in properly written Ada programs variables may not become invalid when standard numeric operations are applied. The language also provides the attribute 'Valid to verify values obtained from unsafe sources e.g. from input, unchecked conversions etc.

As stated above on a machine where Float is implemented by an IEEE 754 machine number, IEEE 754 is permitted leak through. The following program illustrates how this leak can be exploited: <lang Ada> with Ada.Text_IO; use Ada.Text_IO;

procedure IEEE is -- Non portable, bad, never do this!

  Zero  : Float := 0.0;
  PInf  : Float := 1.0 / Zero;
  NInf  : Float := -PInf;
  PZero : Float := 1.0 / PInf;
  NZero : Float := 1.0 / NInf;
  NaN   : Float := 0.0 / Zero; 

begin

  Put_Line (" -oo = " & Float'Image (NInf));
  Put_Line (" +oo = " & Float'Image (PInf));
  Put_Line (" NaN = " & Float'Image (NaN));
  Put_Line ("  -0 = " & Float'Image (NZero));
  Put_Line (" -oo < first " & Boolean'Image (NInf < Float'First));
  Put_Line (" +oo > last  " & Boolean'Image (PInf > Float'Last));
  Put_Line (" NaN = NaN   " & Boolean'Image (NaN = NaN));
  Put_Line ("  -0 = 0     " & Boolean'Image (NZero = 0.0));
  Put_Line ("  +0 = 0     " & Boolean'Image (PZero = 0.0));
  Put_Line ("  +0 < least positive   " & Boolean'Image (PZero < Float'Succ (Zero)));
  Put_Line ("  -0 > biggest negative " & Boolean'Image (NZero > Float'Pred (Zero)));
     -- Validness checks
  Put_Line ("Valid -oo is " & Boolean'Image (NInf'Valid));
  Put_Line ("Valid +oo is " & Boolean'Image (PInf'Valid));
  Put_Line ("Valid NaN is " & Boolean'Image (NaN'Valid));

end IEEE; </lang> The expression -1.0 / 0.0 were non-numeric and thus could not be used. To fool the compiler the variable Zero is used, which circumvents type checks giving desired broken result. Sample output:

 -oo = -Inf*******
 +oo =  +Inf*******
 NaN = NaN********
  -0 = -0.00000E+00
 -oo < first TRUE
 +oo > last  TRUE
 NaN = NaN   FALSE
  -0 = 0     TRUE
  +0 = 0     TRUE
  +0 < least positive   TRUE
  -0 > biggest negative TRUE
Valid -oo is FALSE
Valid +oo is FALSE
Valid NaN is FALSE

AWK

The One True Awk (nawk) uses the native floating-point numbers. We can get the extreme values if these are IEEE numbers. (If you run Awk on a VAX, there are no signed zeros, infinities nor NaN on a VAX.)

Awk raises a fatal error if a program divides by zero. If a call to exp(x), log(x) and sqrt(x) goes out of range, Awk displays a warning and changes the result to 1. Therefore tricks like 1 / 0, or log(0), or sqrt(-1), will not provide the extreme values. There remains some loopholes. Awk never checks for overflow, so we can still get positive or negative infinity. When we have infinity, we can get NaN.

Works with: nawk version 20100523

<lang awk>BEGIN { # This requires 1e400 to overflow to infinity. nzero = -0 nan = 0 * 1e400 pinf = 1e400 ninf = -1e400

print "nzero =", nzero print "nan =", nan print "pinf =", pinf print "ninf =", ninf print

# When y == 0, sign of x decides if atan2(y, x) is 0 or pi. print "atan2(0, 0) =", atan2(0, 0) print "atan2(0, pinf) =", atan2(0, pinf) print "atan2(0, nzero) =", atan2(0, nzero) print "atan2(0, ninf) =", atan2(0, ninf) print

# From least to most: ninf, -1e200, 1e200, pinf. print "ninf * -1 =", ninf * -1 print "pinf * -1 =", pinf * -1 print "-1e200 > ninf?", (-1e200 > ninf) ? "yes" : "no" print "1e200 < pinf?", (1e200 < pinf) ? "yes" : "no" print

# NaN spreads from input to output. print "nan test:", (1 + 2 * 3 - 4) / (-5.6e7 + nan)

# NaN never equals anything. These tests should print "no". print "nan == nan?", (nan == nan) ? "yes" : "no" print "nan == 42?", (nan == 42) ? "yes" : "no" }</lang>


Output from nawk version 2010:

$ awk -f extreme.awk 
nzero = -0
nan = nan
pinf = inf
ninf = -inf

atan2(0, 0) = 0
atan2(0, pinf) = 0
atan2(0, nzero) = 3.14159
atan2(0, ninf) = 3.14159

nan test: nan
nan == nan? yes
nan == 42? yes

The last two lines are wrong. IEEE says that NaN != NaN (and also NaN != 42). The problem is that Awk assumes a == b unless (a - b) < 0 or (a - b) > 0; but NaN - NaN (or NaN - 42) is NaN, and NaN < 0 is false, and NaN > 0 is false, so Awk supposes that NaN == NaN (or NaN == 42) is true.


Output from gawk version 3.1.7:

nzero = 0
nan = NaN
pinf = Inf
ninf = NaN

atan2(0, 0) = 0
atan2(0, pinf) = 0
atan2(0, nzero) = 0
atan2(0, ninf) = 3.14159

ninf * -1 = Inf
pinf * -1 = NaN
-1e200 > ninf? yes
1e200 < pinf? yes

nan test: NaN
nan == nan? no
nan == 42? no

The attempts to use negative zero have failed. GNU awk uses both integers and floating point; GNU awk converted negative zero to an integer and lost the negative sign.

NaN works. Negative infinity seems to work, except when printing. Whenever GNU awk tries to print negative infinity, it prints "NaN".

bc

bc numbers are very different from IEEE floating-point numbers. bc numbers have a variable number of digits. They can always have more digits (until bc has no memory, runs too slow or crashes), so there is no overflow, and no way to reach infinity.

bc also has no negative zero, and no NaN.

Works with: OpenBSD bc
$ bc
# trying for negative zero
-0
0
# trying to underflow to negative zero
-1 / 2
0
# trying for NaN (not a number)
0 / 0
dc: divide by zero
0
sqrt(-1)
dc: square root of negative number
dc: stack empty
dc: stack empty

C

Works with: gcc version 4.4.3

<lang C>#include <stdio.h>

int main() {

   double inf = 1/0.0;
   double minus_inf = -1/0.0;
   double minus_zero = -1/ inf ;
   double nan = 0.0/0.0;
   printf("positive infinity: %f\n",inf);
   printf("negative infinity: %f\n",minus_inf);
   printf("negative zero: %f\n",minus_zero);
   printf("not a number: %f\n",nan);
   /* some arithmetic */
   printf("+inf + 2.0 = %f\n",inf + 2.0);
   printf("+inf - 10.1 = %f\n",inf - 10.1);
   printf("+inf + -inf = %f\n",inf + minus_inf);
   printf("0.0 * +inf = %f\n",0.0 * inf);
   printf("1.0/-0.0 = %f\n",1.0/minus_zero);
   printf("NaN + 1.0 = %f\n",nan + 1.0);
   printf("NaN + NaN = %f\n",nan + nan);
   /* some comparisons */
   printf("NaN == NaN = %s\n",nan == nan ? "true" : "false");
   printf("0.0 == -0.0 = %s\n",0.0 == minus_zero ? "true" : "false");
   return 0;

}</lang>

Output:

positive infinity: inf
negative infinity: -inf
negative zero: -0.000000
not a number: -nan
+inf + 2.0 = inf
+inf - 10.1 = inf
+inf + -inf = -nan
0.0 * +inf = -nan
1.0/-0.0 = -inf
NaN + 1.0 = -nan
NaN + NaN = -nan
NaN == NaN = false
0.0 == -0.0 = true

Output using MinGW with gcc 4.5.2 on Windows 7:

positive infinity: 1.#INF00
negative infinity: -1.#INF00
negative zero: -0.000000
not a number: -1.#IND00
+inf + 2.0 = 1.#INF00
+inf - 10.1 = 1.#INF00
+inf + -inf = -1.#IND00
0.0 * +inf = -1.#IND00
1.0/-0.0 = -1.#INF00
NaN + 1.0 = -1.#IND00
NaN + NaN = -1.#IND00
NaN == NaN = false
0.0 == -0.0 = true

D

D V.2 has a pretty comprehensive approach to floating point values, and unlike Ada embraces IEEE 754. This program shows only part of the floating point features supported by D and its Phobos standard library. <lang d>import std.stdio: writeln, writefln; import std.string: format; import std.math: NaN, getNaNPayload;

string toHex(T)(T x) {

   string result;
   ubyte* ptr = cast(ubyte*)&x;
   foreach (i; 0 .. T.sizeof)
       result = format("%02x", ptr[i]) ~ result;
   return result;

}

void main() {

   {
       writeln("Computed extreme float values:");
       float zero     = 0.0f;
       float pos_inf  = 1.0f / zero;
       writeln(" float +oo = ", pos_inf);
       float neg_inf  = -pos_inf;
       writeln(" float -oo = ", neg_inf);
       float pos_zero = 1.0f / pos_inf;
       writeln(" float +0 = ", pos_zero);
       float neg_zero = 1.0f / neg_inf;
       writeln(" float -0 = ", neg_zero);
       float nan      = zero / pos_zero;
       writefln(" float init = %f  %s", nan, toHex(nan));
       writeln();
       writeln("Some float properties and literals:");
       writeln(" float +oo = ", float.infinity);
       writeln(" float -oo = ", -float.infinity);
       writeln(" float +0 = ", 0.0f);
       writeln(" float -0 = ", -0.0f);
       writefln(" float nan = %f   %s", float.nan, toHex(float.nan));
       writefln(" float init = %f  %s", float.init, toHex(float.init));
       writeln(" float epsilon = ", float.epsilon);
       writeln(" float max = ", float.max);
       writeln(" float -max = ", -float.max);
       writeln(" float min_normal = ", -float.min_normal);
   }
   writeln("-----------------------------");
   {
       writeln("Computed extreme double values:");
       double zero     = 0.0;
       double pos_inf  = 1.0 / zero;
       writeln(" double +oo = ", pos_inf);
       double neg_inf  = -pos_inf;
       writeln(" double -oo = ", neg_inf);
       double pos_zero = 1.0 / pos_inf;
       writeln(" double +0 = ", pos_zero);
       double neg_zero = 1.0 / neg_inf;
       writeln(" double -0 = ", neg_zero);
       double nan      = zero / pos_zero;
       writefln(" double init = %f  %s", nan, toHex(nan));
       writeln();
       writeln("Some double properties and literals:");
       writeln(" double +oo = ", double.infinity);
       writeln(" double -oo = ", -double.infinity);
       writeln(" double +0 = ", 0.0);
       writeln(" double -0 = ", -0.0);
       writefln(" double nan = %f   %s", double.nan, toHex(double.nan));
       writefln(" double init = %f  %s", double.init, toHex(double.init));
       writeln(" double epsilon = ", double.epsilon);
       writeln(" double max = ", double.max);
       writeln(" double -max = ", -double.max);
       writeln(" double min_normal = ", -double.min_normal);
   }
   writeln("-----------------------------");
   {
       writeln("Computed extreme real values:");
       real zero     = 0.0L;
       real pos_inf  = 1.0L / zero;
       writeln(" real +oo = ", pos_inf);
       real neg_inf  = -pos_inf;
       writeln(" real -oo = ", neg_inf);
       real pos_zero = 1.0L / pos_inf;
       writeln(" real +0 = ", pos_zero);
       real neg_zero = 1.0L / neg_inf;
       writeln(" real -0 = ", neg_zero);
       real nan      = zero / pos_zero;
       writefln(" real init = %f  %s", nan, toHex(nan));
       writeln();
       writeln("Some real properties and literals:");
       writeln(" real +oo = ", real.infinity);
       writeln(" real -oo = ", -real.infinity);
       writeln(" real +0 = ", 0.0L);
       writeln(" real -0 = ", -0.0L);
       writefln(" real nan = %f   %s", real.nan, toHex(real.nan));
       writefln(" real init = %f  %s", real.init, toHex(real.init));
       writeln(" real epsilon = ", real.epsilon);
       writeln(" real max = ", real.max);
       writeln(" real -max = ", -real.max);
       writeln(" real min_normal = ", -real.min_normal);
   }
   writeln("-----------------------------");
   writeln("Largest possible payload for float NaN, double NaN, real NaN:");
   float f1 = NaN(0x3F_FFFF);
   writeln(getNaNPayload(f1));
   double f2 = NaN(0x3_FFFF_FFFF_FFFF);
   writeln(getNaNPayload(f2));
   real f3 = NaN(0x3FFF_FFFF_FFFF_FFFF);
   writeln(getNaNPayload(f3));

}</lang> Output:

Computed extreme float values:
 float +oo = inf
 float -oo = -inf
 float +0 = 0
 float -0 = -0
 float init = -nan  ffc00000

Some float properties and literals:
 float +oo = inf
 float -oo = -inf
 float +0 = 0
 float -0 = -0
 float nan = nan   7fc00000
 float init = nan  7fa00000
 float epsilon = 1.19209e-07
 float max = 3.40282e+38
 float -max = -3.40282e+38
 float min_normal = -1.17549e-38
-----------------------------
Computed extreme double values:
 double +oo = inf
 double -oo = -inf
 double +0 = 0
 double -0 = -0
 double init = -nan  fff8000000000000

Some double properties and literals:
 double +oo = inf
 double -oo = -inf
 double +0 = 0
 double -0 = -0
 double nan = nan   7ff8000000000000
 double init = nan  7ff4000000000000
 double epsilon = 2.22045e-16
 double max = 1.79769e+308
 double -max = -1.79769e+308
 double min_normal = -2.22507e-308
-----------------------------
Computed extreme real values:
 real +oo = inf
 real -oo = -inf
 real +0 = 0
 real -0 = -0
 real init = -nan  ffffc000000000000000

Some real properties and literals:
 real +oo = inf
 real -oo = -inf
 real +0 = 0
 real -0 = -0
 real nan = nan   7fffc000000000000000
 real init = nan  7fffa000000000000000
 real epsilon = 1.0842e-19
 real max = 1.18973e+4932
 real -max = -1.18973e+4932
 real min_normal = -3.3621e-4932
-----------------------------
Largest possible payload for float NaN, double NaN, real NaN:
4194303
1125899906842623
4610560118520545279

Among other things, it is possible to trap FP hardware exceptions: <lang d>import std.math: FloatingPointControl;

void main() {

   // Enable hardware exceptions for division by zero, overflow to infinity,
   // invalid operations, and uninitialized floating-point variables.
   FloatingPointControl fpc;
   fpc.enableExceptions(FloatingPointControl.severeExceptions);
   double f0 = 0.0;
   double y1 = f0 / f0; // generates hardware exception

}</lang> Output:

object.Error: Invalid Floating Point Operation

Delphi

Tested on Delphi 2009:

<lang Delphi>program Floats;

{$APPTYPE CONSOLE}

uses

 SysUtils;

var

 PlusInf, MinusInf, NegZero, NotANum: Double;

begin

 PlusInf:= 1.0/0.0;
 MinusInf:= -1.0/0.0;
 NegZero:= -1.0/PlusInf;
 NotANum:= 0.0/0.0;
 Writeln('Positive Infinity: ', PlusInf);      // +Inf
 Writeln('Negative Infinity: ', MinusInf);     // -Inf
 Writeln('Negative Zero: ', NegZero);          // -0.0
 Writeln('Not a Number: ', NotANum);           // Nan

// allowed arithmetic

 Writeln('+Inf + 2.0 = ', PlusInf + 2.0);      // +Inf
 Writeln('+Inf - 10.1 = ', PlusInf - 10.1);    // +Inf
 Writeln('NaN + 1.0 = ', NotANum + 1.0);       // Nan
 Writeln('NaN + NaN = ', NotANum + NotANum);   // Nan

// throws exception

 try
   Writeln('+inf + -inf = ', PlusInf + MinusInf);  // EInvalidOp
   Writeln('0.0 * +inf = ', 0.0 * PlusInf);        // EInlalidOp
   Writeln('1.0/-0.0 = ', 1.0 / NegZero);          // EZeroDivide
 except
   on E:Exception do
     Writeln(E.Classname, ': ', E.Message);
 end;
 Readln;

end.</lang>

Euphoria

Translation of: C

<lang Euphoria>constant inf = 1E400 constant minus_inf = -inf constant nan = 0*inf

printf(1,"positive infinity: %f\n", inf) printf(1,"negative infinity: %f\n", minus_inf) printf(1,"not a number: %f\n", nan)

-- some arithmetic

printf(1,"+inf + 2.0 = %f\n", inf + 2.0) printf(1,"+inf - 10.1 = %f\n", inf - 10.1) printf(1,"+inf + -inf = %f\n", inf + minus_inf) printf(1,"0.0 * +inf = %f\n", 0.0 * inf) printf(1,"NaN + 1.0 = %f\n", nan + 1.0) printf(1,"NaN + NaN = %f\n", nan + nan)</lang>

Output:

positive infinity: inf
negative infinity: -inf
not a number: -nan
+inf + 2.0 = inf
+inf - 10.1 = inf
+inf + -inf = -nan
0.0 * +inf = -nan
NaN + 1.0 = -nan
NaN + NaN = -nan

Forth

Works with: GNU Forth

<lang forth> 1e 0e f/ f. \ inf -1e 0e f/ f. \ inf (output bug: should say "-inf") -1e 0e f/ f0< . \ -1 (true, it is -inf)

0e 0e f/ f.     \ nan

-1e 0e f/ 1/f f0< . \ 0 (false, can't represent IEEE negative zero)</lang>

Go

<lang go>package main

import (

   "fmt"
   "math"

)

func main() {

   // compute "extreme values" from non-extreme values
   // (the X in extreme should be larger, in kind of a jagged
   // font, and in Mountain Dew green...)
   var zero float64                         // zero is handy.
   var negZero, posInf, negInf, nan float64 // values to compute.
   negZero = zero * -1
   posInf = 1 / zero
   negInf = -1 / zero
   nan = zero / zero
   // print extreme values stored in variables
   fmt.Println(negZero, posInf, negInf, nan)
   // directly obtain extreme values
   fmt.Println(math.Float64frombits(1<<63),
       math.Inf(1), math.Inf(-1), math.NaN())
   // validate some arithmetic on extreme values
   fmt.Println()
   validateNaN(negInf+posInf, "-Inf + Inf")
   validateNaN(0*posInf, "0 * Inf")
   validateNaN(posInf/posInf, "Inf / Inf")
   // mod is specifically named in "What every computer scientist..."
   // Go math package doc lists many special cases for other package functions.
   validateNaN(math.Fmod(posInf, 1), "Inf % 1")
   validateNaN(1+nan, "1 + NaN")
   validateZero(1/posInf, "1 / Inf")
   validateGT(posInf, math.MaxFloat64, "Inf > max value")
   validateGT(-math.MaxFloat64, negInf, "-Inf < max neg value")
   validateNE(nan, nan, "NaN != NaN")
   validateEQ(negZero, 0, "-0 == 0")

}

func validateNaN(n float64, op string) {

   if math.IsNaN(n) {
       fmt.Println(op, "-> NaN")
   } else {
       fmt.Println("!!! Expected NaN from", op, "  Found", n)
   }

}

func validateZero(n float64, op string) {

   if n == 0 {
       fmt.Println(op, "-> 0")
   } else {
       fmt.Println("!!! Expected 0 from", op, "  Found", n)
   }

}

func validateGT(a, b float64, op string) {

   if a > b {
       fmt.Println(op)
   } else {
       fmt.Println("!!! Expected", op, "  Found not true.")
   }

}

func validateNE(a, b float64, op string) {

   if a == b {
       fmt.Println("!!! Expected", op, "  Found not true.")
   } else {
       fmt.Println(op)
   }

}

func validateEQ(a, b float64, op string) {

   if a == b {
       fmt.Println(op)
   } else {
       fmt.Println("!!! Expected", op, "  Found not true.")
   }

}</lang> Output:

-0 +Inf -Inf NaN
-0 +Inf -Inf NaN

-Inf + Inf -> NaN
0 * Inf -> NaN
Inf / Inf -> NaN
Inf % 1 -> NaN
1 + NaN -> NaN
1 / Inf -> 0
Inf > max value
-Inf < max neg value
NaN != NaN
-0 == 0

Groovy

Translation of: Java

Solution: <lang groovy>def negInf = -1.0d / 0.0d; //also Double.NEGATIVE_INFINITY def inf = 1.0d / 0.0d; //also Double.POSITIVE_INFINITY def nan = 0.0d / 0.0d; //also Double.NaN def negZero = -2.0d / inf;

println(" Negative inf: " + negInf); println(" Positive inf: " + inf); println(" NaN: " + nan); println(" Negative 0: " + negZero); println(" inf + -inf: " + (inf + negInf)); println(" 0 * NaN: " + (0 * nan)); println(" NaN == NaN: " + (nan == nan)); println("NaN equals NaN: " + (nan.equals(nan)));</lang>

Output:

  Negative inf: -Infinity
  Positive inf: Infinity
           NaN: NaN
    Negative 0: -0.0
    inf + -inf: NaN
       0 * NaN: NaN
    NaN == NaN: true
NaN equals NaN: true

Note that the Groovy implementation of 'equals' incorrectly allows that "NaN == NaN" is true. In a correct IEEE implementation NaN is never equal to anything, including itself.

Icon and Unicon

Icon and Unicon don't define minimum or maximum values of reals, or a negative 0.0. Real numbers are implemented as C doubles and the behavior could vary somewhat from platform to platform. Both explicitly check for divide by zero and treat it as a runtime error (201), so it's not clear how you could produce one of these with the possible exception of the value being introduced through externally called code.

J

Extreme values <lang j> Inf=: _

  NegInf=: __
  NB. Negative zero cannot be represented in J. 
  NaN=. _.</lang>

The numeric atom _. (Indeterminate) is provided as a means for dealing with NaN in data from sources outside J. J itself generates NaN errors rather than NaN values and recommends that _. be removed from data as soon as possible because, by definition, they will produce inconsistent results in contexts where value is important.

Extreme values from expressions <lang j> (1 % 0) , (_1 % 0) _ __

  (1e234 * 1e234) , (_1e234 * 1e234)

_ __

  _ + __         NB. generates NaN error, rather than NaN

|NaN error | _ +__

  _ - _          NB. generates NaN error, rather than NaN

|NaN error | _ -_

  %_

0

 %__             NB. Under the covers, the reciprocal of NegInf produces NegZero, but this fact isn't exposed to the user, who just sees zero

0 </lang>

Some arithmetic <lang j> _ + _ _

  __ + __

__

  Inf + 0

_

  NegInf * 0

0</lang>

Java

<lang java>public class Extreme {

   public static void main(String[] args) {
       double negInf = -1.0 / 0.0; //also Double.NEGATIVE_INFINITY
       double inf = 1.0 / 0.0; //also Double.POSITIVE_INFINITY
       double nan = 0.0 / 0.0; //also Double.NaN
       double negZero = -2.0 / inf;
       System.out.println("Negative inf: " + negInf);
       System.out.println("Positive inf: " + inf);
       System.out.println("NaN: " + nan);
       System.out.println("Negative 0: " + negZero);
       System.out.println("inf + -inf: " + (inf + negInf));
       System.out.println("0 * NaN: " + (0 * nan));
       System.out.println("NaN == NaN: " + (nan == nan));
   }

}</lang> Output:

Negative inf: -Infinity
Positive inf: Infinity
NaN: NaN
Negative 0: -0.0
inf + -inf: NaN
0 * NaN: NaN
NaN == NaN: false

MUMPS

ANSI MUMPS

The 1995 Standard MUMPS (X11.1–1995) implementations do not deal with floating point numbers following IEEE 754. Attempting to use a number over the precision of the system results in a <MAXNUMBER> error:

USER>write 3e145
30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
USER>write 3e146
 
<MAXNUMBER>

Intersystems Caché

Caché has the function $DOUBLE which complies with the IEEE 754 standard. The negative zero is indistinguishable from positive zero by operations. The special values evaluate to 0 when converted to a number in a later operation. <lang MUMPS> EXTREMES

 NEW INF,NINF,ZERO,NOTNUM,NEGZERO
 SET INF=$DOUBLE(3.0E310),NINF=$DOUBLE(-3.0E310),ZERO=$DOUBLE(0),NOTNUM=$DOUBLE(INF-INF),NEGZERO=$DOUBLE(ZERO*-1)
 WRITE "Infinity: ",INF,!
 WRITE "Infinity ",$SELECT($ISVALIDNUM(INF):"is a number",1:"is not a number"),!
 WRITE "Negative Infinity: ",NINF,!
 WRITE "Negative Infinity ",$SELECT($ISVALIDNUM(NINF):"is a number",1:"is not a number"),!
 WRITE "Zero: ",ZERO,!
 WRITE "Zero ",$SELECT($ISVALIDNUM(ZERO):"is a number",1:"is not a number"),!
 WRITE "Negative Zero: ",NEGZERO,!
 WRITE "Negative Zero ",$SELECT($ISVALIDNUM(NEGZERO):"is a number",1:"is not a number"),!
 WRITE "Not a Number: ",NOTNUM,!
 WRITE "Not a Number ",$SELECT($ISVALIDNUM(NOTNUM):"is a number",1:"is not a number"),!
 KILL INF,NINF,ZERO,NONNUM,NEGZERO
QUIT

</lang>

Output:

USER>d EXTREMES^ROSETTA
Infinity: INF
Infinity is not a number
Negative Infinity: -INF
Negative Infinity is not a number
Zero: 0
Zero is a number
Negative Zero: 0
Negative Zero is a number
Not a Number: NAN
Not a Number is not a number

OCaml

<lang ocaml># infinity;; - : float = infinity

  1. neg_infinity;;

- : float = neg_infinity

  1. nan;;

- : float = nan

  1. -0.;;

- : float = -0.

  1. -. 0.;;

- : float = -0.

  1. 1. /. 0.;;

- : float = infinity

  1. -1. /. 0.;;

- : float = neg_infinity

  1. -. infinity;;

- : float = neg_infinity

  1. infinity +. neg_infinity;;

- : float = nan

  1. 0. /. 0.;;

- : float = nan

  1. infinity /. infinity;;

- : float = nan

  1. nan = nan;;

- : bool = false

  1. nan == nan;;

- : bool = true

  1. 0. *. infinity;;

- : float = nan

  1. 0. = -0.;;

- : bool = true

  1. 0. == -0.;;

- : bool = false</lang>

Oz

<lang oz>declare Inf = 1.0e234 * 1.0e234 MinusInf = 1.0e234 * ~1.0e234 Zero = 1.0 / Inf MinusZero = 1.0 / MinusInf NaN = 0.0 / 0.0

{System.showInfo "infinite: "#Inf} {System.showInfo "-infinite: "#MinusInf} {System.showInfo "0: "#Zero} {System.showInfo "-0: "#MinusZero}  %% seems to be identical to Zero {System.showInfo "NaN: "#NaN}

{System.showInfo "inf + -inf: "#Inf+MinusInf} {System.showInfo "NaN * 0: "#NaN*0.0} {System.showInfo "0 * NaN: "#0.0*NaN} {System.showInfo "inf * 0: "#Inf*0.0} {System.showInfo "0 * inf: "#0.0*Inf}

{Show NaN == NaN}  %% shows 'true' ! {Show Zero == MinusZero}

{Show 1.0/0.0 == Inf} %% true {Show 1.0/~0.0 == MinusInf} %% true</lang>

Output: <lang oz>infinite: 1.#INF -infinite: -1.#INF 0: 0.0 -0: 0.0 NaN: -1.#IND inf + -inf: -1.#IND NaN * 0: -1.#IND 0 * NaN: -1.#IND inf * 0: -1.#IND 0 * inf: -1.#IND true true true true</lang>

==PARI/GP==\ PARI t_REALs are not IEEE floating-point numbers; in particular they cannot store NaN or infinite values, though the latter are typically represented as [1] and -[1].

PARI t_REAL numbers have a maximum value of

32-bit 161,614,249 decimal digits
64-bit 694,127,911,065,419,642 decimal digits

where is the machine epsilon at the selected precision. The minimum value is the opposite of the maximum value (reverse the sign bit).

Perl

Perl numbers have three formats (integer, floating-point, string) and perlnumber explains the automatic conversions. Arithmetic tends to convert numbers to integers. To get negative zero, one must negate a floating-point zero, not an integer zero. So -0 is "0", -0.0 is "-0", but -(1.0 - 1.0) is again "0" because the result of 1.0 - 1.0 is an integer zero.

Division by zero, sqrt(-1) and log(0) are fatal errors. To get infinity and NaN, use corresponding string and force a numeric conversion by adding zero to it, or prepending a "+" or "-": <lang perl>#!/usr/bin/perl use strict; use warnings;

my $nzero = -0.0; my $nan = 0 + "nan"; my $pinf = +"inf"; my $ninf = -"inf";

print "\$nzero = $nzero\n"; print "\$nan = $nan\n"; print "\$pinf = $pinf\n"; print "\$ninf = $ninf\n\n";

printf "atan2(0, 0) = %g\n", atan2(0, 0); printf "atan2(0, \$nzero) = %g\n", atan2(0, $nzero); printf "sin(\$pinf) = %g\n", sin($pinf); printf "\$pinf / -1 = %g\n", $pinf / -1; printf "\$ninf + 1e100 = %g\n\n", $ninf + 1e100;

printf "nan test: %g\n", (1 + 2 * 3 - 4) / (-5.6e7 * $nan); printf "nan == nan? %s\n", ($nan == $nan) ? "yes" : "no"; printf "nan == 42? %s\n", ($nan == 42) ? "yes" : "no";</lang>

Output:

$nzero = -0
$nan = nan
$pinf = inf
$ninf = -inf

atan2(0, 0) = 0
atan2(0, $nzero) = 3.14159
sin($pinf) = nan
$pinf / -1 = -inf
$ninf + 1e100 = -inf

nan test: nan
nan == nan? no
nan == 42? no

Here is a rare example of NaN and infinity for an integer type. Math::BigInt, a module that comes with Perl, provides integers of arbitrary sizes, but also has NaN, positive infinity, and negative infinity. There is no negative zero.

<lang perl>#!/usr/bin/perl use strict; use warnings;

use Math::BigInt;

my $nan = Math::BigInt->bnan(); my $pinf = Math::BigInt->binf(); my $ninf = Math::BigInt->binf('-');

print "\$nan = $nan\n"; print "\$pinf = $pinf\n"; print "\$ninf = $ninf\n\n";

my $huge = Math::BigInt->new("123456789"); $huge->bmul($huge)->bmul($huge)->bmul($huge);

print "\$huge = $huge\n"; printf "\$ninf + \$huge = %s\n", $ninf->copy()->badd($huge); printf "\$pinf - \$huge = %s\n", $pinf->copy()->bsub($huge); printf "\$nan * \$huge = %s\n", $nan->copy()->bmul($huge); printf "\$nan == \$nan? %s\n", defined($nan->bcmp($nan)) ? "maybe" : "no"; printf "\$nan == \$huge? %s\n", defined($nan->bcmp($huge)) ? "maybe" : "no";</lang>

Output:

$nan = NaN
$pinf = inf
$ninf = -inf

$huge = 53965948844821664748141453212125737955899777414752273389058576481
$ninf + $huge = -inf
$pinf - $huge = inf
$nan * $huge = NaN
$nan == $nan? no
$nan == $huge? no

PicoLisp

PicoLisp has only very limited built-in floating point support, and handles the rest by calling native (typically C) libraries. Minus zero and negative infinity cannot be represented, while NaN is represented by NIL <lang PicoLisp>(load "@lib/math.l")

(exp 1000.0) # Too large for IEEE floats

-> T

(+ 1 2 NIL 3) # NaN propagates

-> NIL</lang>

PureBasic

<lang PureBasic>Define.f If OpenConsole()

 inf = 1/None
 minus_inf  = -1/None
 minus_zero = -1/inf 
 nan = None/None
 
 PrintN("positive infinity: "+StrF(inf))
 PrintN("negative infinity: "+StrF(minus_inf))
 PrintN("positive zero: "+StrF(None))
 PrintN("negative zero: "+StrF(minus_zero)) ; handles as 0.0
 PrintN("not a number: "+StrF(nan))
 PrintN("Arithmetics")  
 PrintN("+inf + 2.0 =  "+StrF(inf + 2.0))
 PrintN("+inf - 10.1 = "+StrF(inf - 10.1))
 PrintN("+inf + -inf = "+StrF(inf + minus_inf))
 PrintN("0.0 * +inf =  "+StrF(0.0 * inf))
 PrintN("1.0/-0.0 =  "+StrF(1.0/minus_zero))
 PrintN("NaN + 1.0 = "+StrF(nan + 1.0))
 PrintN("NaN + NaN = "+StrF(nan + nan))
 PrintN("Logics")
 If IsInfinity(inf): PrintN("Variabel 'Infinity' is infenite"): EndIf
 If IsNAN(nan): PrintN("Variable 'nan' is not a number"): EndIf
 
 Print(#CRLF$+"Press ENTER to EXIT"): Input()

EndIf</lang>

positive infinity: +Infinity
negative infinity: -Infinity
positive zero: 0.0000000000
negative zero: 0.0000000000
not a number: -1.#IND000000
Arithmetics
+inf + 2.0 =  +Infinity
+inf - 10.1 = +Infinity
+inf + -inf = -1.#IND000000
0.0 * +inf =  -1.#IND000000
1.0/-0.0 =  -Infinity
NaN + 1.0 = -1.#IND000000
NaN + NaN = -1.#IND000000
Logics
Variabel 'Infinity' is infenite
Variable 'nan' is not a number

Press ENTER to EXIT

Python

<lang python>>>> # Extreme values from expressions >>> inf = 1e234 * 1e234 >>> _inf = 1e234 * -1e234 >>> _zero = 1 / _inf >>> nan = inf + _inf >>> inf, _inf, _zero, nan (inf, -inf, -0.0, nan) >>> # Print >>> for value in (inf, _inf, _zero, nan): print (value)

inf -inf -0.0 nan >>> # Extreme values from other means >>> float('nan') nan >>> float('inf') inf >>> float('-inf') -inf >>> -0. -0.0 >>> # Some arithmetic >>> nan == nan False >>> nan is nan True >>> 0. == -0. True >>> 0. is -0. False >>> inf + _inf nan >>> 0.0 * nan nan >>> nan * 0.0 nan >>> 0.0 * inf nan >>> inf * 0.0 nan</lang>

<lang python>>>> # But note! >>> 1 / -0.0

Traceback (most recent call last):

 File "<pyshell#106>", line 1, in <module>
   1 / -0.0

ZeroDivisionError: float division by zero >>> # (Not minus infinity)</lang>

Tcl

Tcl includes support in expressions for all IEEE “extreme” values except for NaN, which it throws a catchable exception on encountering numerically. Moreover, all can be just written directly as literals (they are parsed case-insensitively). For example, see this log of an interactive session: <lang tcl>% package require Tcl 8.5 8.5.2 % expr inf+1 Inf % set inf_val [expr {1.0 / 0.0}] Inf % set neginf_val [expr {-1.0 / 0.0}] -Inf % set negzero_val [expr {1.0 / $neginf_val}] -0.0 % expr {0.0 / 0.0} domain error: argument not in valid range % expr nan domain error: argument not in valid range % expr {1/-inf} -0.0</lang> It is possible to introduce a real NaN though numeric computation, but only by using the mechanisms for dealing with external binary data (it being judged better to just deal with it in that case rather than throwing an exception): <lang tcl>% binary scan [binary format q nan] q nan 1 % puts $nan NaN % # Show that it is a real NaN in there % expr {$nan+0} can't use non-numeric floating-point value as operand of "+"</lang>