Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a conversion from double to int be written in portable C

I need to write function like double_to_int(double val, int *err) which would covert double val to integer when it's possible; otherwise report an error (NAN/INFs/OUT_OF_RANGE).

so pseudo code implementation would look like:

if isnan(val):
    err = ERR_NAN
    return 0
if val < MAX_INT:
    err = ERR_MINUS_INF
    return MIN_INT
if ...
return (int)val

There are at least two similar questions on SO: in this answer it's solved in enough clean way, though it's C++ solution - in C we do not have portable digits for signed int. In this answer, it's explained why we cannot just check (val > INT_MAX || val < INT_MIN).

So the only possible clean way i see is to use floating point environment, but it's stated as implementation-defined feature.

So my question: is there any way to implement double_to_int function in cross-platform way (basing only on C standard, even not considering target platforms to support IEEE-754).?

like image 802
Volodymyr Boiko Avatar asked Jun 29 '18 15:06

Volodymyr Boiko


People also ask

Is conversion from double to int possible?

We can convert double to int in java using typecasting. To convert double data type into int, we need to perform typecasting. Typecasting in java is performed through typecast operator (datatype).

Can you convert a double to an int c#?

To convert a Double value to an integer value, use the Convert. ToInt32() method. Int32 represents a 32-bit signed integer.

Can double be converted to int in C++?

You can't simply convert a double to an int in C++ because the word convert doesn't have a specific meaning.


1 Answers

The answer to "Can a conversation from double to int be written in portable C" is clearly "yes".

For example, you could sprintf the floating value to a string, do string-based inspection (i.e. by string-based comparison to max and min values you also sprintf’d), validation, rounding, etc and then sscanf the known-valid string for the final value.

In effect, you’d be moving toward an intermediate representation that’s (a) portable and (b) convenient. C strings are fine at portability, but not so convenient. If you can use external libraries, there are several that are convenient, but whose portability should be confirmed.

For example (which omits rounding):

#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <string.h>

int convert(double inVal) {
    // basic range check - does anybody have an integer format with more than 300 bits?
    if (fabs(inVal) > 1.0E100) {
        printf("well out of range");
        return 1;
    }

    // load string buffer with input
    char buf[110];
    sprintf(buf, "%0105.0f", inVal);

    // do range check on strings
    if (inVal < 0) {
        char minVal[110];
        sprintf(minVal, "%0105d", INT_MIN);
        if (strcmp(buf, minVal) > 0) {
            printf("too small input: %f\n", inVal);
            return -1;  // needs better error signify
        }
    } else {
        char maxVal[110];
        sprintf(maxVal, "%0105d", INT_MAX);
        if (strcmp(maxVal, buf) < 0) {
            printf("too large input: %f\n", inVal);
            return -1;  // needs better error signify
        }
    }

    // do final conversion
    int result;
    sscanf(buf, "%d", &result);

    printf("input: %f result: %d\n", inVal, result);  // diagnostic

    return result;
}

int main()
{
    // test values    
    convert( 0.);
    convert( -123.5);
    convert( 123.5);

    convert( ((double)INT_MIN)-1);
    convert( ((double)INT_MIN));
    convert( ((double)INT_MIN)+1);
    convert( 2.0*((double)INT_MIN));
    convert( ((double)INT_MIN)/2);

    convert( ((double)INT_MAX)-1);
    convert( ((double)INT_MAX));
    convert( ((double)INT_MAX)+1);
    convert( 2.0*((double)INT_MAX));
    convert( ((double)INT_MAX)/2);

    return 0;
}

Which produces the expected conversions (see test cases at end above):

% gcc test.c ; ./a.out
input: 0.000000 result: 0
input: -123.500000 result: -124
input: 123.500000 result: 124
too small input: -2147483649.000000
input: -2147483648.000000 result: -2147483648
input: -2147483647.000000 result: -2147483647
too small input: -4294967296.000000
input: -1073741824.000000 result: -1073741824
input: 2147483646.000000 result: 2147483646
input: 2147483647.000000 result: 2147483647
too large input: 2147483648.000000
too large input: 4294967294.000000
input: 1073741823.500000 result: 1073741824
like image 83
Bob Jacobsen Avatar answered Oct 11 '22 23:10

Bob Jacobsen