Writing numbers with small exponential

Sometimes my code generates numbers like 1e-311 which is smaller than what double can hold. Smallest double is about 1e-308.

When I write such a number to file, it is written as 1e-311.

Then other software like vtk have trouble reading this, since they are outside range of double.

Ideally I would want writef to round them to zero but it does not do that. Is there a solution to this issue ?

For example this code

proc main()
{
   var x : real = 1.0e-311;
   writeln(x);
   writef("%er\n",  x);
   writef("%r\n",  x);
}

prints

1e-311
1.000000e-311
1e-311

though x is less than the smallest double. Should it not be rounded to zero automatically ?

The smallest positive real(64) is about 1.0e-324. The smallest positive normal is 1.0e-308. Anything less is a subnormal floating point number.

And no, writef() should not sen write subnormal numbers as zero because they are in fact not zero.

I would write your own routine to output according to whatever rules you would like.

2 Likes

C has <float.h> and defines DBL_MIN. I believe but I am not sure (I don't know much about floating point representation) that it is the smalles 64-bit floating point normal, etc.. the value is 2.22e-308. Here is a small program that uses this constant (it appears that Chapel does not define it) and prints a real(64) larger than DBL_MIN, else 0.0:

extern {
#include <float.h>
}
proc write_but(const in x: real, const in format: string) {
   var y = if x <= DBL_MIN then 0.0 else x ;
   writef(format,y);
}
write_but(1.0e-311,"%8.3r\n");
write_but(3.47e-57,"%8.3r\n");

Cheers Nelson

2 Likes

Thanks for the helpful replies, Damian and Nelson!

One approach to doing this might be to define a custom serializer, apply it to a fileWriter, and then do all write()/writeln()s to that fileWriter.

[Caveat: I say this as someone who has yet to write a serializer myself, so hope others will correct me if I'm wrong in this suggestion, or if there's a better approach].

-Brad

1 Like

Using the definition of precision(T) I have posted several times before

//  UnderFlow Threshold - the smallest (positive) Normal floating point value
//
//  See also "Underflow and the Reliability of Numerical Software",
//  James DemmeL, 5(4) Dec 1984, SIAM J ScI STAT COMPUT, pp887-919

proc uft(type T) param where isReal(T)
{
    param _1 = 1:uint(numBits(T));

    return (_1 << (precision(T) - _1)).transmute(T);
}

one could craft a generic version of that earlier routine in pure Chapel as

proc write_but(const in x: real(?w), const in format: string)
{
   param UFT = uft(real(w));

   writef(format,if abs(x) < UFT then 0:real(w) else x);
}

Let me know if you cannot find a copy of precision().

Thank you very much for all the answers. I learnt something new, about subnormal numbers.

1 Like