1

I'm trying to output my results to the decimal accuracy the user has input. In other words, if they enter 145, then it outputs to 0 d.p. - if they enter 145.67, it outputs the result to 2 d.p.

I've tried achieving this by trying different things with %.lf but didn't manage to do it so far. Is there a way to do this in C? If so, is there a name for it - so I can learn more about it.

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

int main() {
  // Using long, double or something else?
  double number, fourthRoot;

  printf("Enter a number: ");
  scanf("%lf", &number);

  fourthRoot = sqrt(sqrt(number));

  printf("4th root of number %lf is %.10lf", number, fourthRoot);

  return 0;
}
nocomment
  • 119
  • 6
  • 2
    There is no way `scanf` is going to work for you. You need to parse the input more carefully. – William Pursell Oct 15 '21 at 16:19
  • 1
    What you've asked seems perfectly reasonable, and many have asked it before — but the surprising fact is, it's basically fundamentally impossible. If the user types 145.67, the internal `double` value you actually get will be more like 145.6699999999999874944, and once you've got that number, there's no way to know what the user actually typed. – Steve Summit Oct 15 '21 at 16:23
  • 1
    One technique to know about is `%g`. That will show good precision, it will strip unnecessary trailing 0's, and it will switch to scientific notation, if necessary, for really big or really small numbers. – Steve Summit Oct 15 '21 at 16:27
  • 1
    One more question: do you want to preserve the same number of *places past the decimal*, or the number of *significant digits*? What should the result be if the user enters 0.0000000000000625? – Steve Summit Oct 15 '21 at 16:36
  • 1
    The nameless thing you're looking for is "Read a floating-point number from the user *and* tell me how much precision it had as the user typed it". But it doesn't have a name, because it doesn't exist as standard functionality, although chux's and William Pursell's answers show you how you might try to explicitly achieve it. – Steve Summit Oct 15 '21 at 16:42

2 Answers2

0

Read user input as a line with fgets() or some scanf("%s",...-like code.

char buf[400];
if (fgets(buf, sizeof buf, stdin)) {

And then process the string. One way is with sscanf()

  int n;
  // Get the number and offset to end of scan
  if (sscanf(buf, "%lf%n", &number, &n) == 1) {
    // Look for '.'
    char *dp = strchr(buf, '.');
    if (dp && dp < buf + n) {
      // decimal point found
      int pre = buf + n - dp - 1;
      printf("%.*f\n", pre, number);  

This works OK but does get fooled if exponential notation used. Additional code could look for the E or e (or P, p with hexadecimal FP notation).

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

There are a lot of edge cases that you should worry about, but this should get you started:

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

static int
compute_root(const char *s)
{
    char *end;
    double number = strtod(s, &end);
    if( *end ){
        fprintf(stderr, "Invalid input: %s\n", s);
        return 1;
    }
    char *dp = strchr(s, '.');
    int precision = dp ? end - dp - 1: 0;
    char fmt[256];
    snprintf(fmt, sizeof fmt, "4th root of %%s is %%.%dlf\n", precision);
    printf(fmt, s, pow(number, .25));
    return 0;
}

int
main(int argc, char **argv)
{
    int errors = 0;
    char buf[64];
    if( argc > 1 ){
        while( *++argv ){
            errors += compute_root(*argv);
        }
    } else while( scanf("%63s", buf) == 1 ){
        errors += compute_root(buf);
    }
    return errors ? EXIT_FAILURE : EXIT_SUCCESS;
}

As an exercise, consider inputs like 5.345e4. The above code will output with a precision of 5, but you probably want 3. Handling those cases is non-trivial (for certain definitions of "trivial").

William Pursell
  • 204,365
  • 48
  • 270
  • 300