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