Number.format issue negative numbers

Former Member
Former Member

Hi,

I need to convert a number to a hexadecimal format. In my context, it is important that the output string has a defined length. I am facing issues when appyling the conversion to negative numbers. See the code below. As you can see, the length of output #2 and #3 is 8 instead of 4. Any hint would be appreciated.

Thanks, Adam

Code

var x1 = 18, x2 = -18;
System.println(x1.format("%04X"));
System.println(x2.format("%04X"));
System.println(x2.format("%+04X"));

Output

0012
FFFFFFEE
FFFFFFEE

  • In hex, the first bit can indicate the sign, so using a "+" in the format() really doesn't make much sense. The hex value is showing you the "bits".

    Consider "FF".  Based on context, that can be either -1 or 255 depending on if it is considered a signed or unsigned integer when converting to decimal.   There's no "-FF"

    You could do something like an and with 0x80000000 to check the highest bit and do you'r own sign.

    the reason you see 8 "digits" is the last two lines is because a Number in CIQ is actually 32 bits, and since the hightest bit is 1, you see all 8, while in the first line, the highest bit is 0, and the %04x" is used.

  • The documentation for Number.format() says that behaves similar to that available in printf from the C stdio library. This is what happens when you test that code on a C compiler...

    Code:

    #include <stdio.h>
     
    int main()
    {
        int x1 = 18, x2 = -18;
        printf("%04X\n", x1);
        printf("%04X\n", x2);
        printf("%+04X\n", x2);
    }

    Output:

    0012
    FFFFFFEE
    FFFFFFEE

    You can see for yourself here. You can also take a peek at some pretty good documentation for printf here.

  • If you want to understand why...

    The format specifier %X indicates that you want to display an unsigned hexadecimal integer. There is no such thing as a negative unsigned, no sign would ever be printed. That is why the + flag has no effect. In C/C++, compilers may warn you that the flag is ignored. The GCC C compiler says main.cpp:8:25: warning: '+' flag used with ‘%X’ gnu_printf format [-Wformat=]

    As for why you get the 4 byte values, this is fairly easy to explain as well.

    The negative representation of the positive number N on a 2's complement system is what you get if you flip all the bits in N and add 1. So given the value +18..

    1. 18 is 0x00000012 or 00000000000000000000000000010010.
    2. flip the bits => 0x000000ED or 11111111111111111111111111101101b
    3. add 1 => 0xFFFFFFEE or 11111111111111111111111111101110b

    When you print positive 18 with %04X, you're telling the system to write a minimum of 4 characters, left padding the value with zeroes. So you get 0012. When you print -18, it has the hex value FFFFFFEE, which is larger than the 4 character minimum, so the system displays as many characters as are necessary.

    It isn't clear what you are actually trying to get, but it seems that you want -18 to show up as -0012 (technically I'd hope you'd want to see -0x0012 so that the base is explicit, but whatever). If you want that, you'd have to do something like this..

    function format_signed_hex_value( fmt, value ) {
        var sign;
        if (value < 0) {
            sign = "-";
            value = 0 - value; // positive
        } else {
            sign = "+";
        }
        
        return Lang.format("$1$$2$", sign, value.format(fmt));
    }