Message Boards Message Boards

Control the number of digits in CForm output?

GROUPS:

I would like to print out numbers in C form with exactly 3 digits after the decimal point. E.g.

  • 1.23456*^8 -> 1.234e8
  • 1.0*^8 -> 1.000e8

I thought I could do something like

PaddedForm[CForm[1.23456*^8],{8,3}]

but that didn't work.

CForm[SetPrecision[1.0*^8 ,4]] 

also fails to give 3 digits after the decimal point.

POSTED BY: Mark Alford
Answer
2 months ago

Mark,

This is actually very hard -- there is no simple way to do it. I posted a similar question here in my post but got no replies and even had tech support look at it and had little resolution. I came up with an approach that works by wrapping the numbers in a temporary function and after turning everything into CForm, doing a string replace. Here is some sample code. mapReplace goes through an expression and replaces the Real numbers with a dummy function acf[ paddedform ]. You can edit the paddedForm below to get your desired format.

mapReplace[exp_] := 
 MapAt[acf[
    ToString[
     PaddedForm[#, {8, 3}, 
      NumberFormat -> (Row[{#1, If[#3 != "", "e", ""], #3}] &)]]] &, 
  exp, Position[exp, _Real]]

after this you do a stringReplace to clean it all up:

CNumberReformat[expr_] := 
 StringReplace[ ToString[mapReplace[expr], CForm], 
  Shortest["acf(\"" ~~ x__ ~~ "\")"] :> "(" <> x <> ")"]

To use it:

equation = 25.32032 - 4.55 x + 16.0006 z + 2 y + 234.2341*^8
CNumberReformat[equation]

to get

2y + z( 16.001) + ( 2.342e10) + x*( -4.550)

I hope this helps.

POSTED BY: Neil Singer
Answer
2 months ago

Mark,

Did this work for you?

POSTED BY: Neil Singer
Answer
2 months ago

Thank you for your suggestion. What I was really hoping for was something like the C/Python "%e" format, that always produces a string of the same length, so it could be used, for example, to print data in nicely aligned columns:

 1.000e12
-1.000e9 
 1.000e3 
-1.000e1 
 1.000e0 
-1.000e-1 

If I understand it correctly, your proposal for an individual number would be something like

CFormat[x_,n_,f_]:= ToString[
 PaddedForm[x, {n, f}, 
  NumberFormat -> (Row[{#1, If[#3 != "", "e", ""], #3}] &) 
 ]
]

but that doesn't create strings of a fixed length, e,g,

"<" <> CFormat[1.0*^6,9,3] <> ">" 
<      1.000e6>
"<" <> CFormat[10,9,3] <> ">"
<     10.000>

I still don't understand how PaddedForm works. In the example above, the "9" that gets passed to PaddedForm doesn't cause it to produce a string of length 9: the actual output is much longer.

POSTED BY: Mark Alford
Answer
2 months ago

If you define the format function as follows:

format[x_] := 
 ToString[PaddedForm[x, {4, 3}, 
   NumberFormat -> (Row[{#1, If[#3 != "", "e", ""], #3}] &), 
   ExponentFunction -> (# &)]]

It will do the formatting you want. I added the ExponentFunction option. By always returning its argument (#,&), you ALWAYS get exponential notation. (If you want to limit exponential notation to a range of exponents, you can change the function -- see the documentation examples). You can add this format to what I posted above by doing this:

mapReplace[exp_] := MapAt[acf[format[#]] &, exp, Position[exp, _Real]]

You can get almost any formatting you want this way but it requires studying the PaddedForm options carefully.

If you really want C formatting, you can very easily call a C sprintf external and print your numbers (and use the code I posted above to apply it to all the numbers in your equations). I have done this in the past (for similar reasons) and I post my code here so you can use it. See the .nb file for instructions. You will need the c file (I had to use a .txt extension to be able to post it). and a .tm file (same name change required). The command I put in the notebook is for a Mac but you can do the same on the PC by looking at the WSTP documentation (for Mac) (for windows).

Using this external function you will get the full functionality of C sprintf for formatting a single number. If you want a more general sprintf function you can edit my C code and tm file to get what you need.

I hope this helps.

POSTED BY: Neil Singer
Answer
2 months ago

Group Abstract Group Abstract