Does this number have more than ten decimal places?

Let's say I want to write a function that does the following:

Given the number N,
when N is rounded to the digits D1,
does the result make more than D2 a decimal place, not counting the trailing zeros?

For example, N is .01001, D1 is 4, and D2 is 2. The question becomes, does .0100 include more than two decimal places, not counting trailing zeros? And the answer is no. "But if N was .00101, the answer would be yes.

I am looking for an efficient way to do this using the standard C library functions, taking into account the limitations of floating point numbers.

An example of my intended use: show the number using four digits if necessary, but otherwise show it using two digits.

(This is not a question of homework - it is the result of a professional programmer who did not do these homework when he was a student.)

+3
source share
5 answers

The only easy way to do this with the standard library is to use snprintf(or simply sprintf) with the correct format, and then calculate the zeros yourself. Correct decimal representation of a (binary) floating point number is a very difficult task that you do not want to try to do on your own, and you have almost zero chance to write the correct version, which is faster than the standard library.

Hope I got it right; it is not verified:

double n; /* the number N */
int d1, d2; /* the parameters d1 and d2 */
char s[MAXLEN], *z;
snprintf(s, sizeof s, "%.*f", d1, n);
for (z=s+strlen(s)-1; *z==0; z--);
if (strlen(++z)<d1-d2) puts("yes");
else puts("no");

: ssianky, snprintf . C - , , IEEE, POSIX DECIMAL_DIG , (, ) , . , , d1 , , , snprintf, . ( GNU Microsoft.)

d1, . , 10.

2: OP " ", snprintf . , , . %g printf , OP...

+4

10 ^ D1 , , 10 ^ D2. , , .., , , .

, , , . .

int f (double N, unsigned int D1, unsigned int D2)
{
   int i, n_mult_round, ten_d2;
   /* instead of the loop below, a real implementation should use */
   /* N *= dbl_powers_of_ten[D1]; */
   /* where dbl_powers_of_ten is a double array containing powers of ten */
   for (i = 0; i < D1; ++i) {
      N *= 10.0;
   }
   n_mult_round = (int) round (N);
   /* instead of the loop below, a real implementation should use */
   /* ten_d2 = int_powers_of_ten[D2]; */
   /* where int_powers_of_ten is an int array containing powers of ten */
   ten_d2 = 1;
   for (i = 0; i < D2; ++i) {
      ten_d2 *= 10;
   }
   if ( n_mult_round % ten_d2 == 0 ) {
      return ( 1 );
   }
   else {
      return ( 0 );
   }
}
+1
  • .
  • , .

:

char buff[20]; /* make as big as necessary */
int maxPrecision = 4;
int minPrecision = 2;

sprintf(buff, "%.*f", maxPrecision, myFloat);

char *p = buff + (strlen(buff) - 1);
char *punct = strchr(buff, ".");

/* remove trailing zeros until we reach minPrecision */
while (*p == '0' && p > (punct + minPrecision))
    *p-- = 0; 
0
source

How about this? fmod should return decimal places after the specified number of decimal places, so we can compare these two numbers to make sure they are equal.

int needsD1Decimals(float N, int D1, int D2) {
    float pow1 = pow(0.1f, D1); // 0.0001
    float pow2 = pow(0.1f, D2); // 0.01
    float mod1 = fmod(N, pow1); // 0.00001
    float mod2 = fmod(N, pow2); // 0.00001
    if (fabs(mod1 - mod2) > (pow1 / 2)) { // > 0.00005 to handle errors
        return 1;
    }
    return 0;
}

If you just want to print the correct answer, most likely just print it with the most decimal places and trim the zeros at the end:

void printNumber(float N, int D1, int D2) {
    char format[256];
    char result[256];
    sprintf(format, "%%.%df", D1);
    sprintf(result, format, N);
    char *end = result + strlen(result) - 1;
    int zeros = 0;
    while (end > result && end[0] == '0' && zeros < (D1 - D2))
    {
        zeros++;
        end--;
    }
    if (zeros >= (D1 - D2))
    {
        end[1] = '\0';
    }
    puts(result);
}

void doNumber(float N, int D1, int D2) {
    printf("%f, %d, %d: ", N, D1, D2);
    printNumber(N, D1, D2);
    printf("\n");
}

int _tmain(int argc, _TCHAR* argv[])
{
    doNumber(0.01001f, 4, 2);
    doNumber(0.010101f, 4, 2);
    doNumber(0.011001f, 4, 2);
    doNumber(5000.0f, 4, 2);
    return 0;
}
0
source
int foo(float number, int d1, int d2)
{
    assert((number > 0.0f) && (number < 1.0f) && (d1 <= FLT_DIG) && (d2 < d1) && (d2 > 0));

    int count = d1;
    int n = (int)(number * pow(10.0f, d1));

    if (n == 0) return 0;

    while ((n % 10) == 0)
    {
        n /= 10;
        count--;
    }

    return (count > d2) ? 1 : 0;
}
-1
source

Source: https://habr.com/ru/post/1765915/


All Articles