C How to calculate percentage (perthousands) without floating point precision

How do you calculate the percentage of 2 int values โ€‹โ€‹into an int value that represents a percentage (perthousands for greater accuracy)?

Background / purpose: Using a processor that does not have an FPU, floating point calculations take up 100 times more.

int x = 25;
int y = 75;
int resultPercentage; // desire is 250 which would mean 25.0 percent

resultPercentage = (x/(x+y))*1000; // used 1000 instead of 100 for accuracy
printf("Result= ");
printf(resultPercentage);

exit:

Result = 0

When really what I need is 250. And I canโ€™t use ANY floating point calculations.

An example of a normal fpu calculation:

int x = 25;
int y = 75;
int resultPercentage; // desire is 250 which would mean 25.0 percent

resultPercentage = (int)( ( ((double)x)/(double(x+y)) ) *1000); //Uses FPU slow

printf("Result= ");
printf(resultPercentage);

exit:

Result = 250

But the result came from the use of floating point calculations.

+4
source share
7 answers

resultPercentage = (x/(x+y))*1000; (x/(x+y)), , 0 1 , *1000. :

x/(x+y), a = x b = x+y, a/b, :

result = (a + b/2)/b;

% a/b

result = (100*a + b/2)/b;

permil โ€ฐ a/b

result = (1000*a + b/2)/b;

permyriad โ€ฑ a/b

result = (10000*a + b/2)/b;

@ H2CO3 , , (long, long long) , , x+y.

result = (100L*a + b/2)/b;

,

// printf(resultPercentage);
printf("%d\n", resultPercentage);
+4

(x * 1000 + 5) / (10 * (x + y))

,

(x * 100) / (x + y)

.


"", , 1000, perthousands. , , , , 10000 1000 .

, . , , ( ) long long:

(x * 1000ll + 5) / (10ll * (x + y))

(- ).

+3

- ... , , , , , (, , ). (, ?) - " ", BigDecimal - , ( a malloc/free). () ( ), ; , ( ) , .

- , printf . ; , , " " . , , , divide-and-sprintf ( ). - , " " ( , , / ...).

EDIT , ( , ). : .

, !

#include <stdio.h>
#include <time.h>

void doRound(char *s, int n) {
  // round the number string in s
  // from the nth digit backwards.
  // first digit = #0
  int ii;
  int N = n;
  if(s[n] - '0' < 5) {
    s[N] = '\0';
    return; // remove last digit
  }
  while (n-- > 0) {
    if(s[n] == '.') {
      n--;
    }
    if(s[n] - '0' < 9) {
      s[n]++;
      s[N] = '\0';
      return;
    }
    s[n] = '0';
  }
  if (n == -1) {
    for (ii = N-1; ii >=0; ii--) {
     s[ii+1] = s[ii];
    }
    s[0] = '1';
  }
  else s[N] = '\0';
}

void longDivision(unsigned int a, unsigned int b, char* r, int n) {
// implement b / a using only integer add/subtract/multiply
  char temp[20];  // temporary location for result without decimal point
  char c = '0';   // current character (digit) of result
  int ci = 0;     // character index - location in temp where we write c
  int t = n + 1;  // precision - no more than n digits
  int dMult = 0;  // scale factor (log10) to be applied at the end
  int di = 0;

  // first get numbers to correct relative scaling:
  while( a > b) {
    dMult++;
    b *=10;
  }
  while (10 * a < b) {
    dMult --;
    a*=10;
  }

  // now a >= b: find first digit with addition and subtraction only
  while( b > a ) {
    c++;
    b -= a;
  }
  t--;
  temp[ci++] = c; // copy first digit
  c = '0';

  // now keep going; stop when we hit required number of digits
  while( b > 0 && t > 0) {
    b *= 10;
    t--;
    while( b > a ) {
      c++;
      b -= a;
    }
    temp[ ci++ ] = c;
    c = '0';
  }

  // copy the result to the output string:
  temp[ ci ] = '\0'; // terminate temp string
  if (dMult > 0) {
    r[ di++ ] = '0';
    r[ di++ ] = '.';
    while( --dMult > 0 ) {
      r[ di++ ] = '0';
    }
    ci = 0;
    while( temp[ ci ] != '\0' ) {
     r[ di++ ] = temp[ ci++ ];
    }
  }
  else {
    ci = 0;
    while( temp[ ci ] != '\0') {
      r[ di++ ] = temp[ ci++ ];
      if( dMult++ == 0 ) r[ di++ ] = '.';
    }
  }
  r[ di ] = '\0';

  // finally, do rounding:
  doRound(r, n+1);

}


int main(void) {
  int a, b;
  time_t startT, endT;
  char result[20];
  int ii;

  a = 123; b = 700;
  longDivision(a, b, result, 5);
  printf("the result of %d / %d is %s\n", b, a, result);

  printf("the actual result with floating point is %.5f\n", (float) b / (float) a );

  a = 7; b = 7000;
  longDivision(a, b, result, 5);
  printf("the result of %d / %d is %s\n", b, a, result);

  a = 3000; b = 29999999;
  longDivision(a, b, result, 5);
  printf("the result of %d / %d is %s\n", b, a, result);

  startT = clock();
  for(ii = 1; ii < 100000; ii++) longDivision(a, ii, result, 5);
  endT = clock();
  printf("time taken: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);
  // and using floating point:
  startT = clock();
  for(ii = 1; ii < 100000; ii++) sprintf(result, "%.4f", (float) ii / (float) a);
  endT = clock();
  printf("with floating point, time taken: %.2f ms\n", (endT - startT) * 1000.0 / CLOCKS_PER_SEC);
  return 0;
}

( ):

the result of 700 / 123 is 5.6911
the actual result with floating point is 5.69106
the result of 7000 / 7 is 1000.00
the result of 29999999 / 3000 is 10000.0
time taken: 16.95 ms
with floating point, time taken: 35.97 ms
+2

resultPercentage = (x*1000)/(x+y);
0

. :

resultPercentage = (x * 1000)/(x + y); .

0

:

int x = 25;
int y = 75;
int resultPercentage; // desire is 250 which would mean 25.0 percent

resultPercentage = (x*1000)/(x+y);

printf("Result= ");
printf(resultPercentage);
0

- , , 1000 1024

1000 ,

resultRelation = (x < 10)/(x + y);

10 . 1000. , , , .

,

if(resultPercentage > 500) do something

if(resultRelation > 512) do something

. , , 0-1024 0-1000,

0

All Articles