2

My code is taking a string format and compose it into a buffer (without sprintf, itoa etc).

I'm having trouble converting a float number to string, as I need to have precision of at most 7 digits with no trailing zeros. as well as convert each number in the float variable to char (but in that matter I don't need any help).

I tried several methods, all including math calculations, but nothing has brought me to the desired outcome. Here's my code so far, but it is messy and also sometimes gives incorrect outcome. I also believe there is a more clean and less-complicated way to do it. any help will be widely appreciated.

            if (*format == 'f') {
                float f = *(float*)ptrs[counter];
                char str[30];
                int b, c, m, k = 7, i = 0, l = 0;
                int a = f;
                f -= a;
                while (k >= 0) {
                    l = pow(10, k);
                    m = a / l;
                    if (m > 0) {
                        break;
                    }
                    k--;
                }
                printf("%d", k);
                for (l = k + 1; l > 0; l--) {
                    b = pow(10, l - 1);
                    c = a / b;
                    str[i++] = c + 48;
                    a %= b;
                }
                str[i++] = '.';
                for (l = 0; l < 7; l++) {
                    f *= 10.0;
                    b = f;
                    str[i++] = b + 48;
                    f -= b;
                }
                for (i = 0; i < 7; i++) {
                    *buffer = str[i];
                    buffer++;
                }
                counter++;
                str[i] = '\0';

for example:

input: float v2 =0.9372;
output: .937199
desired output: 0.9372

input: float v2 =0.25000;
output: 1.25000
desired output: 0.25

5
  • Show a minimal reproducible example, including the code that calls this code, the input used, the output obtained, and the output desired. Commented May 27, 2020 at 11:51
  • 4
    You cannot in general convert a number in a binary floating-point format to decimal using powers of ten because multiplying or dividing by powers of ten in a binary format adds rounding errors, distorting the number being converted. For a full solution, you need to use some form of extended precision or advanced techniques. If you only need to convert numbers in a limited domain, there may be easier partial solutions for that domain. You would need to specify the domain, such as numbers less than 10^6, converted with at most six significant digits. Commented May 27, 2020 at 11:57
  • @EricPostpischil if i understood you correctly, i need only a precision of at most 7 digits. Commented May 27, 2020 at 12:03
  • @pmg without use of sprintf. Commented May 27, 2020 at 12:14
  • comment deleted after the edit Commented May 27, 2020 at 12:15

1 Answer 1

3

he's messy and also sometimes gives incorrect outcome

At some point given the base 2 nature of typical floating point, the programmer needs to make choices:

With common floating point encoding, there are also issues of

  • Infinity

  • Not-a-number.

  • Oddities like -0.0

And how portable to make the code?


Sources of inexactness

OP's use of int limits float to about [INT_MIN...INT_MAX]. Code fails for float much outside that range. Could use long long to get some more range without a great deal of code change. Better yet research float modff(float value, float *iptr).

float f = ...;
// int a=f;
long long a=f;

Repeated use of f*=10.0 below with a fractional value in f injects a possible rounding (inexactness), at each iteration.

for(l=0;l<7;l++) {
  f*=10.0;

Code makes no effort to round given that f may not be 0.0 after the fraction forming for(l=0;l<7;l++) { f*=10.0; loop. I see this as a place to improve precision. This area is also tricky as the round-up may effect many leading digits when they are 9, eventually needing a shift of the string buffer. In the 0.93721, after this loop, f was about 0.74. Since more than 0.5, a rounding would have given the answer of ".9371999" --> ".9372000".

Code aims for 7 decimal digits after the .. Values, as a decimal in code, assigned to a float match to 6 to 9 significant decimal places - which includes digits to the left of .. Expectations should not get too high.


Improvement idea

When the number of fraction digits desired is small, perform 1 scaling/round

// ASSUME f >= 0.0, (sign handling done before here)
long long a=f;
f-=a;
int int_f = round(f*pow(10, 7));
if (int_f < 10000000) {
  later_printf_the_7_digits(int_f);
} else {
  a++;
  later_printf_the_7_digits(0);
}
Sign up to request clarification or add additional context in comments.

2 Comments

Reinstate Monice what do you exactly mean by "later_printf_the_7_digits"?
Code here breaks f into a whole number parts and fraction part. Presumable, you want to print the whole number part first and later print the fraction part.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.