2
$\begingroup$

In my current macro, I have:

Put[Chop[someList], "someFile"];

where "someList" is a mixed bag of "strings", "integers", "exact complex values" (e.g. (-1)^(1/3)) and "numeric floating point complex values". The Chop function nicely cleans all numeric elements which are close to zero. I am now looking for a way to specify the format string for non-zero "numeric floating point values", which would output at most some number of "significant" decimal digits (e.g. 7, instead of the default 17).

An example of my "someList":

someList = {{{"a string"}, {1, 2}}, {{3, 4}, {Exp[I/3], (-1)^(2/3)}}, {{5, 6}, {1.23456789 + 9.87654321*I, -9.87654321 + 1.23456789*I}}};

for which, I would like to get (assuming 6 "significant digits"):

{{{"a string"}, {1, 2}}, {{3, 4}, {E^(I/3), (-1)^(2/3)}}, {{5, 6}, {1.23457 + 9.87654*I, -9.87654 + 1.23457*I}}}

Update (2019.08.14): It seems that, despite repeated requests that can be found in the Internet, Mathematica does not provide any C-like "printf" (low level) formatted output conversion functionality. For the time being, I (mostly) solved my problem by using this trick:

InexactToExact[x_Real] := 
  Which[PossibleZeroQ[Chop[FullSimplify[x]]], 0, 
        PossibleZeroQ[Chop[FullSimplify[x - 1]]],  1, 
        PossibleZeroQ[Chop[FullSimplify[x + 1]]], -1, 
        PossibleZeroQ[Chop[FullSimplify[x - 3]]],  3, 
        PossibleZeroQ[Chop[FullSimplify[x + 3]]], -3, 
        PossibleZeroQ[Chop[FullSimplify[x - 1/3]]],  1/3, 
        PossibleZeroQ[Chop[FullSimplify[x + 1/3]]], -1/3, 
        PossibleZeroQ[Chop[FullSimplify[x - Sqrt[3]]]],  Sqrt[3], 
        PossibleZeroQ[Chop[FullSimplify[x + Sqrt[3]]]], -Sqrt[3], 
        PossibleZeroQ[Chop[FullSimplify[x - Sqrt[3]/3]]],  Sqrt[3]/3, 
        PossibleZeroQ[Chop[FullSimplify[x + Sqrt[3]/3]]], -Sqrt[3]/3, 
        (* and so on for any "special" real value that you need *) 
        True, x] (* all another real values *)
InexactToExact[z_Complex] := 
  Which[PossibleZeroQ[Chop[FullSimplify[z]]], 0, 
        PossibleZeroQ[Chop[FullSimplify[z - (-1)^(1/3)]]],  (-1)^(1/3), 
        PossibleZeroQ[Chop[FullSimplify[z + (-1)^(1/3)]]], -(-1)^(1/3), 
        PossibleZeroQ[Chop[FullSimplify[z - (-1)^(1/3)*Sqrt[3]]]],  (-1)^(1/3)*Sqrt[3], 
        PossibleZeroQ[Chop[FullSimplify[z + (-1)^(1/3)*Sqrt[3]]]], -(-1)^(1/3)*Sqrt[3], 
        PossibleZeroQ[Chop[FullSimplify[z - (-1)^(1/3)/Sqrt[3]]]],  (-1)^(1/3)/Sqrt[3], 
        PossibleZeroQ[Chop[FullSimplify[z + (-1)^(1/3)/Sqrt[3]]]], -(-1)^(1/3)/Sqrt[3], 
        (* and so on for any "special" complex value that you need *) 
        InexactNumberQ[z], FullSimplify[(InexactToExact[Re[z]]) + (InexactToExact[Im[z]]) * I], 
        True, z] (* all another complex values *)
InexactToExact[v:Except[_Real | _Complex]] := v (* all another types of values *)

someList = Replace[Chop[FullSimplify[someList]], {v_:>InexactToExact[v]}, {-1}];
Put[someList, "someFile"];

Unfortunately, the above trick does not work for many "exact" values. It seems to me that the problem is that Mathematica returns "Complex" for Head[3+I] and Head[3*I] but it happily returns "Plus" and "Times" for, respectively, Head[Sqrt[3]+I] and Head[Sqrt[3]*I].

$\endgroup$
  • $\begingroup$ NumberForm[#,{\[Infinity],7}] or the same with DecimalForm, which gives only decimal form without scientific notation. $\endgroup$ – Alx Aug 5 at 9:19
  • $\begingroup$ Thanks. I tried Put[NumberForm[Chop[someList], {\[Infinity],7}], "someFile"]; but, in the file, it simply saves "NumberForm[originalText, {\[Infinity],7}]". $\endgroup$ – Wile E. Aug 5 at 9:46
  • $\begingroup$ Yu may use Export function: Export["somefile",Map[NumberForm[Chop[#], {\[Infinity], 7}] &,Table[{x, x^2, Sin[x]}, {x, 0, \[Pi], 0.1}],{2}],"Table"]. I used generated table here to show exporting to file with 3 columns of numbers of desired form. $\endgroup$ – Alx Aug 5 at 10:15
  • $\begingroup$ Thanks again. It still doesn't work, sorry (I added an example of my "someList" above and, as one can see, I would need a solution which automatically deals with nested lists of different kinds of elements). Another problem with NumberForm is that it always outputs all "requested" digits, including the trailing zeros (e.g. one gets 0.0000000 instead of simply 0.). $\endgroup$ – Wile E. Aug 5 at 10:47
  • $\begingroup$ I think I would need a way to modify the "format string" for the lowest level routine which writes numeric floating point values in the InputForm (used by the Put function). $\endgroup$ – Wile E. Aug 5 at 11:21
1
$\begingroup$

Updated to handle numbers in scientific notation

You could block the formatting of Real objects:

Block[{Real},
    Format[r_Real, InputForm] := StandardForm @ NumberForm[
        r,
        3,
        NumberFormat -> (Replace[#3, {"" -> #1, _ -> StringJoin[#1, "*^", #3]}]&)
    ];
    Put[someList, "tstfile.txt"]
]

Check:

Import["tstfile.txt"]

"{{{\"a string\"}, {1, 2}}, {{3, 4}, {E^(I/3), (-1)^(2/3)}}, {{5, 6}, {1.23 + 9.88*I, -9.88 + 1.23*I}}}"

$\endgroup$
  • $\begingroup$ @WileE. See update. $\endgroup$ – Carl Woll Aug 14 at 17:37
  • $\begingroup$ Thanks. I decided to go one step further and convert "inexact" numbers into "exact" ones (see my "update" above). Fortunately, I only need to deal with several tens of various "magic" values. $\endgroup$ – Wile E. Aug 14 at 18:28

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.