I work on some performance contests between different datatypes,
and fell in the trap that GNU 'C' somehow supports int128 / __int128 / __int128_t
and the like, but can't handle constants for them, has no read or print routines, not even a print format specifier.
Seeked around and found lot's of - IMHO - insufficient info / attempts, tried to put some of it together, and build something that allows read and print to and from console and string.
As I'm far! from 'experienced programmer' I'd like a pro review against mistakes
and 'good coding', as well as evtl. hints on other solutions better covering the topic, and / or improvement(s) to make it more universal.
( It's far from anything I can grasp how we have these types since years, and no programming support for them ... ??? Evtl. I overlooked something? )
The code as of now:
/*
* Based on others work, see below, thus no copyright claim,
* alas in chaotic trial and error not all sources noted,
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Check to match / fullfill evtl. restrictions / copyrights of the origins.
* 2. As well for using / distributing source code as binaries.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// issue, goal: GNU gcc / glibc programming workbench provides 128-bit integers
// with different names ( __int128, int_128? int_128_t? ), already confusing,
// it doesn't provide read routine, print routine or print format specifier,
// the web is flooded with naive questions and insuffucient solutions, found
// something nearly covering at:
// "Codeforces / DrinkMoreBoilingWater's blog / some tips about __int128 "
// - https://codeforces.com/blog/entry/75044 ,
// shortcomings AFAICT: console only, print fails for INT128_MIN,
// further sources: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html ,
// tried to: xxxx
// not yet covered: read leading '+', other print formatting,
// usage: no prerequisites,
// build / tested: linux ( debian ), GNU gcc, glibc 2.40, Intel xeon hardware,
// standalone: compile with 'gcc -O2 -o int128_test_5 int128_test_5.c',
// run with: './int128_test_5 xxxx' where xxxx is a string to read, convert,
// re-convert and print.
// The rest is commented or self-explanatory.
#include <stdio.h> // reg. e.g. printf, putchar,
// #include <stdlib.h> // not necc. here?
#include <string.h> // reg. e.g. strcpy,
// max: 170141183460469231731687303715884105727
// max: -170141183460469231731687303715884105728
volatile int i = 0; // global variables defined before 'macros',
char str[ 45 ];
char *ptr = str;
__int128_t myatoi( const char *s ) { // string to int128 from ???,
const char *p = s;
__int128_t neg = 0, val = 0;
// Skip leading whitespace
while ((*p == '\n') || (*p == '\t') || (*p == ' ') ||
(*p == '\f') || (*p == '\r') || (*p == '\v')) {
p++;
}
// Check for sign
if ((*p == '-') || (*p == '+')) {
if (*p == '-') {
neg = 1;
}
p++;
}
// Convert string to number
while (*p >= '0' && *p <= '9') {
if (neg) {
val = (10 * val) - (*p - '0');
} else {
val = (10 * val) + (*p - '0');
}
p++;
}
return val;
}
void print(__int128 x) { // print int128 to console from ???,
if( x >= 0 ) {
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
} else {
putchar('-');
x = -x;
if( x + 1 < 0 )
printf( "170141183460469231731687303715884105728" );
else {
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
}
}
void i128tostr_2( char target[ 45 ], __int128 x ) { // recursive subroutine for i128tostr,
char *tptr = target;
if( x >= 0 ) {
if (x > 9) i128tostr_2( target, x / 10 );
tptr[ i ] = ( x % 10 + '0' );
i++;
} else {
if( -x + 1 < 0 ) { // special casing INT128_MIN,
strcpy( target, "-170141183460469231731687303715884105728" );
i = 40;
return;
} else {
tptr[ i ] = '-';
i++;
x = -x;
i128tostr_2( target, x );
}
}
}
void i128tostr( char target[ 45 ], __int128 x ) { // converting int128 into 0-terminated ASCII string, recursive approach,
char *tptr = target; // header to set i and append tail independet from recursion,
i = 0;
i128tostr_2( target, x );
tptr[ i ] = '\0';
}
int main( int argc, char *argv[] ) {
#ifdef __SIZEOF_INT128__
printf( " size of INT128: %1d \n", __SIZEOF_INT128__ );
#else
printf( " INT128 likely not supported. \n" );
#endif
/// strcpy( str, "-1234567890123456789012345678901234567890" ); // example setting the string,
/// printf( "string: %s \n", str ); // example output to console,
/// ptr[2] = '9'; // Change // example changing a digit,
/// printf( "string: %s \n", str ); // example printing the changed string,
/// strcpy( str, "1" );
/// printf( "string: %s \n", str );
strcpy( str, "-9223372036854775810ll" );
__int128_t num = myatoi(str);
printf("Converted number: %llu\n", num); // insufficient, wraps at LONG_MAX ,
print( num );
printf( "\n" );
strcpy( str, "170141183460469231731687303715884105727" ); // INT128_MAX,
num = myatoi(str);
print( num );
printf( "\n" );
num = myatoi( argv[ 1 ] ); // read command line argument,
print( num );
printf( "\n" );
i128tostr( str, num ); // convert to string and print,
printf( "string: %s \n", str );
strcpy( str, "-170141183460469231731687303715884105728" ); // INT128_MIN,
printf( " " ); // alignment,
num = myatoi(str);
print( num );
printf( "\n" );
i128tostr( str, num ); // same num -> string -> print,
printf( "string: %s \n", str );
i128tostr( str, -9223372036854775808ll ); // convert constant, !! doesn't work < INT64_MIN, > INT64_MAX,
printf( "string: %s \n", str );
i128tostr( str, -1 ); // convert constant, !! doesn't work < INT64_MIN, > INT64_MAX,
printf( "string: %s \n", str );
i128tostr( str, -0 ); // convert constant, !! doesn't work < INT64_MIN, > INT64_MAX,
printf( "string: %s \n", str );
i128tostr( str, 0 ); // convert constant, !! doesn't work < INT64_MIN, > INT64_MAX,
printf( "string: %s \n", str );
i128tostr( str, 1 ); // convert constant, !! doesn't work < INT64_MIN, > INT64_MAX,
printf( "string: %s \n", str );
i128tostr( str, 9223372036854775807ll ); // convert constant, !! doesn't work < INT64_MIN, > INT64_MAX,
printf( "string: %s \n", str );
strcpy( str, "170141183460469231731687303715884105727" ); // INT128_MAX,
num = myatoi(str);
printf( " " ); // alignment,
print( num );
printf( "\n" );
i128tostr( str, num ); // same num -> string -> print,
printf( "string: %s \n", str );
return 0;
}