*Post by Mat Nieuwenhoven*I recently needed itoa for base 36. I discovered that for negative numbers

OpenWatcom's itoa delivers a positive result, except when the base is 10.

So -1 will only be -1 in text for base 10, not e.g. for base 9.

This behaviour is documented.

I wonder what the reasoning behind this is. Any ideas?

Another point is that when I examined an alternative written in C (OW libs

implemenattion is in assembly), that the C alternative was much quicker.

A test that ran for 15 seconds with the OW lib implementation took only 10

with the C implementation, implemented as a subroutine in the same source

file. I find this quite strange.

Mat Nieuwenhoven

Below is the code I was testing with. Rename to itoa_test.c.

/*********************************************************

*

* Test various itoa implementations.

* For OpenWatcom, compile with "wcl386 itoa_test -i=%watcom%\h -otax"

*

*********************************************************/

#include <limits.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

int main(int argc, char *argv[]);

char *itoa_GPL3(int value, char* result, int base);

char *itoa_public(int value, char* result, int base);

int main(int argc, char *argv[])

{

int i, base;

char *p;

char bufferOW[8 * sizeof(int) + 2];

char bufferGPL3[8 * sizeof(int) + 2];

char bufferPublic[8 * sizeof(int) + 2];

int increment = 1000;

int errors;

time_t StartTime, EndTime;

// First, do the test using OpenWatcom's lib version

StartTime = time(NULL);

printf("\nTesting OW atio\nbase:");

for (base = 2; base <= 36; base++)

{

errors = 0;

if (base == 2)

printf("%d", base);

else

printf(",%d", base);

flushall(); // Show the output

for (i = INT_MIN; i <= (INT_MAX - increment); i += increment)

{

p = itoa(i, bufferOW, base);

if (!p

|| p[0] == 0 && i != 0)

{

if (++errors > 1) // Allow 1 error (INT_MIN))

break;

}

}

if (errors < 2 // Make sure very last value is tested too

&& i != INT_MAX)

{

p = itoa(INT_MAX, bufferOW, base);

if (!p

|| p[0] == 0 && i != 0)

{

if (++errors > 1) // Allow 1 error (INT_MIN))

break;

}

}

}

EndTime = time(NULL);

printf("\nRun time for OW lib atoi %d seconds\n", EndTime - StartTime);

// Secondly, do the test using an GPL3 source version found on the web

StartTime = time(NULL);

printf("\nTesting GPL3 atio\nbase:");

for (base = 2; base <= 36; base++)

{

errors = 0;

if (base == 2)

printf("%d", base);

else

printf(",%d", base);

flushall(); // Show the output

for (i = INT_MIN; i <= (INT_MAX - increment); i += increment)

{

p = itoa_GPL3(i, bufferGPL3, base);

if (!p

|| p[0] == 0 && i != 0)

{

if (++errors > 1) // Allow 1 error (INT_MIN))

break;

}

}

if (errors < 2

&& i != INT_MAX)

{

p = itoa(INT_MAX, bufferGPL3, base);

if (!p

|| p[0] == 0 && i != 0)

{

if (++errors > 1) // Allow 1 error (INT_MIN))

break;

}

}

}

EndTime = time(NULL);

printf("\nRun time for GPL3 atoi %d seconds\n", EndTime - StartTime);

// Thirdly, do the test using an public domain source version found on

the web

StartTime = time(NULL);

printf("\nTesting public atio\nbase:");

for (base = 2; base <= 36; base++)

{

errors = 0;

if (base == 2)

printf("%d", base);

else

printf(",%d", base);

flushall(); // Show the output

for (i = INT_MIN; i <= (INT_MAX - increment); i += increment)

{

p = itoa_public(i, bufferPublic, base);

if (!p

|| p[0] == 0 && i != 0)

{

if (++errors > 1) // Allow 1 error (INT_MIN))

break;

}

}

if (errors < 2

&& i != INT_MAX)

{

p = itoa(INT_MAX, bufferOW, base);

if (!p

|| p[0] == 0 && i != 0)

{

if (++errors > 1) // Allow 1 error (INT_MIN))

break;

}

}

}

EndTime = time(NULL);

printf("\nRun time for public domain atoi %d seconds\n\n", EndTime -

StartTime);

// Fourthly, compare the outputs.

// OW doesn't prepend a - sign if the base is not 10???

for (base = 2; base <= 36; base++)

{

errors = 0;

printf("testing base %d\n", base);

for (i = INT_MIN; i <= (INT_MAX - increment); i += increment)

{

itoa(i, bufferOW, base);

itoa_GPL3(i, bufferGPL3, base);

itoa_public(i, bufferPublic, base);

if (strcmp(bufferOW, bufferGPL3) != 0

|| strcmp(bufferOW, bufferPublic) != 0)

{

printf("itoa mismatch: base %d, value decimal %i = hex

%X\n\tOW : %s\n\tGPL3 : %s\n\tpublic: %s\n",

base, i, i, bufferOW, bufferGPL3, bufferPublic);

if (++errors > 1) // allow INT_MIN error

break;

}

}

}

return 0;

}

/***********************************************************

* C++ version 0.4 char* style "itoa":

* Written by Lukßs Chmela

* Released under GPLv3.

************************************************************/

char *itoa_GPL3(int value, char* result, int base)

{

char *ptr = result,

*ptr1 = result,

tmp_char;

int tmp_value;

// check that the base if valid

if (base < 2 || base > 36)

{

*result = '\0';

return result;

}

do

{

tmp_value = value;

value /= base;

*ptr++ =

"zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35

+ (tmp_value - value * base)];

} while ( value );

// Apply negative sign

if (tmp_value < 0) *ptr++ = '-';

*ptr-- = '\0';

while(ptr1 < ptr)

{

tmp_char = *ptr;

*ptr--= *ptr1;

*ptr1++ = tmp_char;

}

return result;

}

/***************************************************************

* itoa code not covered by GPL3

*

http://www.daniweb.com/software-development/c/threads/148080/itoa-function-o

r-similar-in-linux

* Reformatted and commented for clarity, and modified with

* extra checks, and allow negative values for non-base10.

* Fixed string reversal

***************************************************************/

/* The Itoa code is in the puiblic domain */

char* itoa_public(int value, char* result, int base)

{

static char dig[] = "0123456789abcdefghijklmnopqrstuvwxyz";

int n = 0, neg = 0;

unsigned int v;

char *p, *q;

char c;

// check that the base if valid

if (base < 2 || base > 36)

{

*result = '\0';

return result;

}

if (value < 0)

{

neg = 1;

value = -value;

}

v = value;

do

{

result[n++] = dig[v%base];

v /= base;

} while (v);

if (neg)

result[n++] = '-';

result[n] = '\0';

// Doing pointer changes not in the for() is slightly faster

for (p = result, q = p + n - 1; p < q; )

c = *p, *p++ = *q, *q-- = c;

return result;

}