« Flip the Bird | Main | Women... »

August 13, 2005

Rounding with strfmon on Solaris

A friend of a friend had a problem last week with strfmon on Solaris. He annoyingly refused to give any details about Solaris versions but he did provide a small code segment:

#include <stdio.h>
#include <errno.h>
#include <locale.h>
#include <monetary.h>
 
int main (int ac, char **av)
{
    const char* strfmonfmt="%^10.0n";
    double val = 99.49;
    char str[64];
 
    setlocale (LC_MONETARY, "en_AU");
    strfmon (str, sizeof(str), strfmonfmt, val);
    printf ("%.2f = %s\n", val, str);
    return 0;
}
This FOAF also suggested plugging other values in for val.

Well the example did what it should and produced a right-aligned value of 99. Tests on various other values worked as well so I had to ask for some more clues while pointing out that the code (as provided) was not doing appropriate error-checking on the return value of the strfmon call.

The FOAF suggested making "small" changes to to val, so I tried '99.5' and got a right-aligned "00" instead of the expected "100". Obviously the routine works out the number of places to display before actually rounding the number. This means that any rounding attempts which change the number of integer digits demonstrates the same funny behaviour.

This is a real, genuine, absolutely uncompromising, 100% bug. You could log it with Sun and wait for a patch.... but why not work out a way around the problem - after all, the purpose of strfmon is not really to round numbers (that is more like a side effect). How about doing an IEEE approved round of the number before using strfmon - it will take a few more cycles but it means that we are using the right routines for the right tasks. Also note that for this example, the error code is pretty slap-dash*.

The code appears in the extended entry, just in case some of you want to solve it on your own (in which case don't read any further...

Oh, and for the Mac fans out there, this code works correctly on the Mac. I even tried identical versions of gcc - works on the Mac, fails on Solaris. That suggests the bug is really in the library.

Note that the inclusion of math.h may require you to include the math library (-lm or -lmath) when you compile this code. Check your local manpage and of course YMMV**...

[* i.e. cobbled together - should be written much better...]

[** Your Milage May Vary...]

#include <stdio.h>
#include <errno.h>
#include <locale.h>
#include <monetary.h>
#include <math.h>
 
int main (int ac, char **av)
{
    const char* strfmonfmt="%^10.0n";
    double val = 99.51;
    char str[64];
 
    setlocale (LC_MONETARY, "en_AU");
    if (strfmon (str, sizeof(str), strfmonfmt, rint(val)) == -1)
    {
        printf("Error in strfmon\n") ;
    }
    printf ("%.2f = %s\n", val, str);
    return 0;
}

Posted by Ozguru at August 13, 2005 06:00 AM