0

Here's what I'm trying to do:

  • I need to print the fractional part of a floating number which has to be input as a float during user input.
  • The fractional part should be like: if float is 43.3423, the output should be 3423; and if number is 45.3400 output should be 3400.
  • This can be done easily with a string input but I need a way to make this work with float without losing the extra zeros or without appending zeros to user's original input.

Here's what I already tried :-

  • Take the fractional part by frac = num - (int)num and then multiplying frac until we get zero as the remainder. But this fails for cases like 34.3400 — the last two zeros won't get included with this method.
  • Convert the float number to a string by

    char string[20];
    sprintf(string, "%f", float_number);
    

The sprintf function puts the float number as a string but here also it doesn't automatically detect the user entered precision and fills the string with extra zeros at the end (6 total precision). So here also the information about the user's original entered precision is not obtained.

So, is there a way to get this done? The number must be taken as float number from user. Is there any way to get info about what's the user's entered precision? If it's not possible, an explanation would be very helpful.

4
  • 6
    You can't do it because the floating point value doesn't retain information about how it was created and with what precision it was input. You also have the natural rounding problems with floating point values, so a value entered by a user might not be representable exactly by a float. In short, without using strings as input it's simply not possible. Commented Aug 8, 2017 at 6:27
  • Keeping the hint of @Someprogrammerdude in mind... You could get the input as string, counting the digits after decimal point, converting string input to float afterwards (e.g. using atof() or strtod()), and using the counted number for output formatting. It sounds like quite much effort (a lot of character fiddling and many places where error checking should be done). I would think twice about whether the "pretty looking output" is worth the implementation effort... Commented Aug 8, 2017 at 6:57
  • ya ur right , actually I was only trying to find if there's a way to detect user's entered precision by taking initial input itself as float, but i get ur point anyway. thanks . Commented Aug 8, 2017 at 8:06
  • What you need are decimal floating point numbers that retain precision; Python programming language has those. It cannot be achieved easily, if at all, with IEEE 754 binary floating point numbers as are often used in C. Commented Aug 8, 2017 at 8:51

3 Answers 3

1

I think I understand where you're coming from. E.g. in physics, it's a difference whether you write 42.5 or 42.500, the number of significant digits is implicitly given. 42.5 stands for any number x: 42.45 <= x < 42.55 and 42.500 for any x: 42.4995 <= x < 42.5005.

For larger numbers, you would use scientific notation: 1.0e6 would mean a number x with x: 950000 <= x < 1050000.

A floating point number uses this same format, but with binary digits (sometimes called bits ;)) instead of decimal digits. But there are two important differences:

  • The number of digits (bits) used depends only on the data type of the floating point number. If your data type has e.g. 20 bits for the mantissa, every number stored in it will have these 20 bits. The mantissa is always stored without a part after the "decimal" (binary?) point, so you won't know how many significant bits there are.
  • There's no direct mapping between bits and decimal digits. You will need roughly 3.5 bits to represent a decimal digit. So even if you knew a number of significant bits, you still wouldn't know how many significant decimal digits that would make.

To address your problem, you could store the number of significant digits yourself in something like this:

struct myNumber
{
    double value;
    int nsignificant;
};

Of course, you have to parse the input yourself to find out what to place in nsignificant. Also, use at least double here for the value, the very limited precision of float won't get you far. With this, you could use nsignificant to determine a proper format string for printing the number with the amount of digits you want.

This still has the problem mentioned above: you can't directly map decimal digits to bits, so there's never a guarantee your number can be stored with the precision you intend. In cases where an exact decimal representation is important, you'll want to use a different data type for that. C# provides one, but C doesn't. You'd have to implement it yourself. You could start with something like this:

struct myDecimal
{
    long mantissa;
    short exponent;
    short nsignificant;
}

In this struct, you could e.g. place 1.0e6 like this:

struct myDecimal x = {
    .mantissa = 1;
    .exponent = 6;
    .nsignificant = 2;
};

Of course, this would require you to write quite a lot of own code for parsing and formatting these numbers.

Sign up to request clarification or add additional context in comments.

Comments

0

which has to be input as a float during user input.

So, is there a way to get this done.

Almost. The "trick" is to note the textual length of user input. The below will remember the offset of the first non-whitespace character and the offset after the numeric input.

scanf(" %n%f%n", &n1, &input, &n2);

n2 - n1 gives code the length of user input to represent the float. This method can get fooled if user input is in exponential notation, hexadecimal FP notation, infinity, Not-a-number, excessive leading zeros, etc. Yet works well with straight decimal input.

The idea is to print the number to a buffer with at least n2 - n1 precision and then determine how much of the fractional portion to print.

Recall that float typically has about 6-7 significant leading digits of significance, so attempting to input text like "123456789.0" will result in a float with the exact value of 123456792.0 and the output will be based on that value.

#include <float.h>
#include <math.h>

int scan_print_float(void) {
  float input;
  int n1, n2;
  int cnt = scanf(" %n%f%n", &n1, &input, &n2);
  if (cnt == 1) {
    int len = n2 - n1;
    char buf[len * 2 + 1];
    snprintf(buf, sizeof buf, "%.*f", len, input);
    char dp = '.';
    char *p = strchr(buf, dp);
    if (p) {
      int front_to_dp = p + 1 - buf;
      int prec = len - front_to_dp;
      if (prec >= 0) {
        return printf("<%.*s>\n", prec, p+1);
      }
    }
  }
  puts(".");
  return 0;
}

int main(void) {
  while (scan_print_float()) {
    fflush(stdout);
  }
  return EXIT_SUCCESS;
}

Input/Output

43.3423
<3423>
45.3400
<3400>
-45.3400
<3400>
0.00
<00>
1234.500000
<500000>
.
.

To robustly handle this and the various edge cases, code should read user input as text and not as a float.


Note: float can typically represent about 232 numbers exactly.
43.3423 is usually not one of them. Instead it has an exactly value of 43.3423004150390625

43.3400 is usually not one of them. Instead it has an exactly value of 43.340000152587890625

Comments

0

The only way is to create a struct with the original string value and/ or required precision for rounding

Comments

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.