Reputation: 486
I have a C/C++ application that writes numeric values into redis as a string. I also have a Java application that will read these values out of redis. On occasion for valid reasons, we end up with a floating-point value that has a value of NaN
or -NaN
. However, when using sprintf(charPtr, "%e", dblVal);
, the value is output as nan
. I also tried the same statement with %E
, and it resulted in NAN
. When Java attempts to parse via Float.parseFloat()
or Double.parseDouble
it throws a NumberFormatException.
This application has been ported from Solaris to Linux and subsequently gone through some Linux upgrades and at some point "NaN" became "nan". I can't say for certain on what upgrade ultimately introduced this behavior.
I have gone through an excercise utilizing cmath's std::isfinite()
and std::isnan()
and can ultimately define my own valid (-)NaN
or (-)Infinity
strings, but this doesn't seem like I need to be reinventing normalized NaN and Infinity strings. Infinity may be a bit different as the C side outputs inf
yet Java wants Infinity
.
Ultimately I need to be able to decode data written by the C++ app in Java. nan and inf cannot be decoded by Java as written. My focus was on NaN, but Infinity is a case that should be covered.
Upvotes: 0
Views: 2098
Reputation: 486
A potentially more universal option would be to convert the floating-point number into hex when written to redis and then converted back when read. This would ensure that there wouldn't be any precision loss by converting it to a decimal string, but also cover the +/-Inf and NaN cases.
This is possible since both sides are using IEEE floating-point numbers.
Upvotes: 0
Reputation: 133919
The Linux case is (a) correct behaviour according to ISO/IEC 9899:2001:
[
%e
,%E
][...] A
double
argument representing an infinity or NaN is converted in the style of anf
orF
conversion specifier.
and the text for
A double argument representing an infinity is converted in one of the styles
[-]inf
or[-]infinity
-- which style is implementation-defined. A double argument representing a NaN is converted in one of the styles[-]nan
or[-]nan(n-char-sequence)
-- which style, and the meaning of any n-char-sequence, is implementation-defined. The F conversion specifier producesINF
,INFINITY
, orNAN
instead ofinf
,infinity
, ornan
, respectively.277)
I.e. the safest in Java would be to try to parse the double, and if that fails, lowercase the String
and test the existence of -
as the first character and the remainder after the possible sign with .startsWith("nan")
and .startsWith("inf")
Of course this doesn't help if you need to support the non-standards-conforming Windows C runtimes.
Upvotes: 1
Reputation: 52364
Why not just use something like this in your java code for parsing a double?
double parseDouble(String s) throws NumberFormatException {
try {
return Double.valueOf(s);
} catch (NumberFormatException e) {
if (s.equalsIgnoreCase("nan")) {
return Double.NaN;
} else if (s.equalsIgnoreCase("inf") || s.equalsIgnoreCase("+inf")) {
return Double.POSITIVE_INFINITY;
} else if (s.equalsIgnoreCase("-inf")) {
return Double.NEGATIVE_INFINITY;
} else {
throw e; // Invalid string
}
}
}
Upvotes: 1