Skip to main content
Added hint on similar C++ project.
Source Link

[edit] Hint: a similar project for C++20 which - as far as I see - also manages bigger than 128-bit integers can be found at: Infinite precision integer in C++20 . [/edit]

I work on some performance contests between different datatypes, and fell in the trap that GNU 'C' somehow supports int128 / __int128 / __int128_t and and the like, but can't handle constants for them, has no read or print routines, not even a print format specifier.

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.

[edit] Hint: a similar project for C++20 which - as far as I see - also manages bigger than 128-bit integers can be found at: Infinite precision integer in C++20 . [/edit]

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.

Became Hot Network Question
edited tags
Source Link
toolic
  • 16.4k
  • 6
  • 29
  • 221

As I'm far! from 'experienced programmer'an 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.

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.

As I'm far from an 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.

Post Migrated Here from codereview.meta.stackexchange.com (revisions)
Source Link

int128 handling in c-code, gcc / glibc / linux

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; 
}