2
$\begingroup$

In MMA I have a 2d matrix whose each entry is a irrational number(in fraction format in MMA). Say:

{{-4,           -(2/Sqrt[5]),  0]},
 {-(4/Sqrt[20]), -4,            -Sqrt[2]},
 {1,            0,             0}} 

Now I would like to convert it into decimals and save as much precision as possible before feeding it into C++.

I learnt that 16 significant decimal places is the limit of double precision in C++. So I would like to convert the matrix above into one with scientific notation with entries like:

1.1234567890123456E10

or

1.1234567890123456E-10

Then I can make the best use of 16 digits in the double precision and give the matrix directly to C++.

Here comes the question:

  1. how could I convert the fractions into the "E" notation?

and

  1. save the matrix in a plain text file friendly to the Eigen Library I'm using? See the format here: Example
matrix << 1,0,1,0,
          1,0,1,0,
          1,0,1,0,

I have tried ScientificForm but what was exported was like:

ScientificForm[-0.816496580927726]...

What if I just need the numbers in E notation?

$\endgroup$
  • $\begingroup$ Something like CForm[$MachineEpsilon]? $\endgroup$ – J. M. will be back soon May 9 '16 at 3:12
  • $\begingroup$ @J.M. I tried CForm, FortranForm, the same as the ScientificForm[-0.816496580927726] $\endgroup$ – James May 9 '16 at 3:18
  • $\begingroup$ That would be due to the fact that the number is not large enough or small enough to warrant scientific notation. Are you asking that numbers like 1.6 and -0.754 all be expressed scientifically, or do you have a minimum and maximum threshold? $\endgroup$ – J. M. will be back soon May 9 '16 at 3:21
2
$\begingroup$

You can use NumberFormat option in ScientificForm to do this. For example

cformat[x_, numDigts_] := 
 ToString[
   ScientificForm[x, numDigts, NumberFormat -> (Row[If[#3 == "", {#1}, {#1, "E", #3}]] &)]]

then

cformat[1.2345678*^-10, 4]
(* "1.235E-10" *)

However, since your data is all in the range of 0 to 10, there would be no "E" in the results:

data = {{-4, -(2/Sqrt[3]), 0}, {-(4/Sqrt[3]), -4, -Sqrt[2]}, {1, 0, 0}};
StringRiffle[StringRiffle[#, "\t"] & /@ Map[cformat[#, 10] &, N@data, {-1}], "\n"]

(*
-4. -1.154700538    0.
-2.309401077    -4. -1.414213562
1.  0.  0.
*)

If you like to make the format line up together nicely and always have the "E", here is a version modified from george2079's answer:

f77Eform[x_?NumericQ, fw_Integer, ndig_Integer] := 
 Module[{sig, s, p, ps}, {s, p} = MantissaExponent[x];
  {sig, ps} = {ToString[Round[10^ndig Abs[s]]], ToString[Abs[p]]};
  StringJoin @@ 
   Join[Table[" ", {fw - ndig - 7}], 
    If[x < 0, "-", " "], {"0."}, {sig}, 
    Table["0", {ndig - StringLength[sig]}], {"E"}, 
    If[p < 0, {"-"}, {"+"}], Table["0", {2 - StringLength[ps]}], {ps}]]

toCformat2D[A_, numDigts_: 8] := Module[{lth, lineToString},
  lth = Length[A];
  lineToString[ls_] := StringRiffle[ToString /@ f77Eform[#, 2*numDigts, numDigts] & /@ ls, "\t"];
  StringRiffle[Table[lineToString[A[[n]]], {n, 1, lth}], "\n"]
  ]



toCformat2D[data, 10]
(* 
  "-0.4000000000E+01       -0.1154700538E+01        0.0000000000E-307
   -0.2309401077E+01       -0.4000000000E+01       -0.1414213562E+01
    0.1000000000E+01        0.0000000000E-307       0.0000000000E-307" 
*)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.