14

I want to control the number of exponent digits after 'e' in C printf %e?

For example, C printf("%e") result 2.35e+03, but I want 2.35e+003, I need 3 digits of exponent, how do I use printf?

Code:

#include<stdio.h>
int main()
{
    double x=34523423.52342353;
    printf("%.3g\n%.3e",x,x);
    return 0;
}

Result: http://codepad.org/dSLzQIrn

3.45e+07
3.452e+07

I want

3.45e+007
3.452e+007

But interestingly, I got the right results in Windows with MinGW.

user1024
  • 982
  • 4
  • 13
  • 26
  • 4
    The "Windows" behavior is non-conforming and VS2015 will use at least 2 exponents digits by default (see [*exponent formatting*](https://msdn.microsoft.com/en-us/library/vstudio/bb531344%28v=vs.140%29.aspx)). – cremno Jul 10 '15 at 03:36
  • @cremno With what is "Windows" non-conforming concerning exponent width? Other than conforming or not to OP's goal? – chux - Reinstate Monica Jul 10 '15 at 04:25
  • @cremno I see "...The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent. ..." §7.21.6.1 – chux - Reinstate Monica Jul 10 '15 at 14:54
  • @chux: Yes, that's the reason why it isn't conforming to C99/C11. The rationale also contains: “For `%e`, C99 clarifies that small exponents contain at least 2 digits, but no more than are necessary to represent the value. Prior to C99, it was not clear that an arbitrary number of leading zeros were not allowed.” – cremno Jul 10 '15 at 15:06
  • @cremno Too bad, that at the time of C99 a control mechanism was not defined that would address this. IMO, a minimum of 2 is an odd choice - likely prior art. At _least_, the spec should define a constant of the maximum width expected. This would aid in right-sizing `"%e"` buffers. Else code needs something like `ilog10(DBL_MAX_10_EXP)+1`. Thanks for this insight. – chux - Reinstate Monica Jul 10 '15 at 15:14

3 Answers3

10

"...The exponent always contains at least two digits, and only as many more digits as necessary to represent the exponent. ..." C11dr §7.21.6.1 8

So 3.45e+07 is compliant (what OP does not want) and 3.45e+007 is not compliant (what OP wants).

As C does not provide a standard way for code to alter the number of exponent digits, code is left to fend for itself.

Various compilers support some control.

visual studio _set_output_format

For fun, following is DIY code

  double x = 34523423.52342353;
  //                    - 1 . xxx e - EEEE \0
  #define ExpectedSize (1+1+1 +3 +1+1+ 4 + 1)
  char buf[ExpectedSize + 10];
  snprintf(buf, sizeof buf, "%.3e", x);
  char *e = strchr(buf, 'e');  // lucky 'e' not in "Infinity" nor "NaN"
  if (e) {
    e++;
    int expo = atoi(e);
    snprintf(e, sizeof buf - (e - buf), "%05d", expo);  // 5 more illustrative than 3
  }
  puts(buf);

  3.452e00007

Also see c++ how to get "one digit exponent" with printf

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks, I finally use `_set_output_format` to get the same result. – user1024 Jul 22 '15 at 11:58
  • 1
    First, Nice answer! Regarding the question _[here](http://stackoverflow.com/q/37187540/645128)_, this answer would also a good fit. I am just not sure how it works. `e` in `snprintf` is the target buffer, but `buf` is modified with the result. How? – ryyker May 12 '16 at 13:48
  • @ryyker `snprintf(buf, sizeof buf, "%.3e", x);` forms the exponential string version of `x`. So `buf` should have an `'e'` in it right before the exponential digits. Then code reads from `buf` just after `'e'` to get the exponent. Then it it prints it _back_ to `buf` with `snprintf(e, sizeof buf ...`, this time with the desired formatting. In this case `"%05d"`, in [that case](http://stackoverflow.com/q/37187540/645128), use `"%d"`. – chux - Reinstate Monica May 12 '16 at 13:57
  • This answer has convinced me to just use search and replace to get to what I need... thanks! – Eric Bringley Oct 12 '18 at 18:01
1

printf Format tags prototype:

%[flags][width][.precision][length]specifier

The precision

... This gives ... the number of digits to appear after the radix character for a, A, e, E, f, and F conversions ... .

You are using the conversion and the precision specifier correctly, the difference is with the implementations of the C library function and the environments on the differing systems. The precision specifies the number of digits after the '.' (dot, period, etc..). It does not set the number of characters that represent the exponentiation. The facts that it provides 3 digits on windows is just the way windows specifies the format, not the way the C standard library specifies that printf will work.

It would take comparing how the source implementations differ to see what is relied on for that piece of the format string. (it will probably boil down to some obscure difference in the way the windows v. linux/unix environments/locale/etc. are defined or specified)

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
  • oh I see, bad c/c++, it's not truly cross platform. Is it due to the difference of os or compilers? is there any compiler get the same result with win mingw? – user1024 Jul 10 '15 at 03:35
  • 1
    Not "bad C++", but "bad Microsoft". It´s cleary specified what `%e` etc. should do, but MS gives a sh* (there are so many things like that in VS that it´s just sad) – deviantfan Jul 10 '15 at 03:38
  • 2
    Well, this is where that nasty thing quasi-related to **implementation defined** comes into play. Since the number of digits in the exponentiation isn't specified as part of the standard, different compilers are free to implement that part however they like. It may even be that the mingw implementation is the **exact same** as the normal unix/linux glibc implementation, but the part of the OS environment relied upon in forming that part is different between windows/mingw/linux/etc... It's a tough one. That's why you need to figure out what is actually used in the final output. **fun...** – David C. Rankin Jul 10 '15 at 03:39
  • So, I can't get the exact same result between Windows and Linux? – user1024 Jul 10 '15 at 06:33
  • 1
    @DavidC.Rankin: This is not implementation-defined at all. ISO C (at least C99 and C11 and I believe also C89) specify the exact formatting for floating point formats, and the MS library is wrong. – R.. GitHub STOP HELPING ICE Jul 11 '15 at 05:49
  • 1
    I stand corrected. I looked at the man page and skimmed the standard but must have missed the digit specification for the exponentiation. Old eyes.... – David C. Rankin Jul 12 '15 at 08:47
-3
char *nexp(double x, int p, int n) // Number with p digits of precision, n digits of exponent.
{
 const int NN=12;
 static char s[NN][256];//(fvca)
 static int i=-1;
 int j,e;

 i=(++i)%NN; // Index of what s is to be used...
 sprintf(s[i],"%.*lE", p,x); // Number...
 for(j=0; s[i][j]; j++) if(s[i][j]=='E') break; // Find the 'E'...
 if(s[i][j]=='E') // Found!
  {
   e= atoi(s[i]+j+1);
   sprintf(s[i]+j+1, "%+0*d", n+1,e);
   return s[i];
  }
 else return "***";
}


// Best Regards, GGa
// G_G
GGa
  • 1
  • 1
    `i=(++i)%NN;` - Please do not write code like this (i.e. increments inside an expression). Getting into this habit will lead to problems in the future. – Ed Heal Dec 19 '18 at 12:17
  • OK, changed to: ++i%=NN; – GGa Dec 19 '18 at 13:42
  • 1
    Also using `static` is a bad idea - as it prevents the code from being used in MT environments – Ed Heal Dec 19 '18 at 14:22
  • The behavior of `i=(++i)%NN;` is not defined by the C standard: “If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined” (C 2018 6.5 2). – Eric Postpischil Sep 15 '19 at 14:35