1
$\begingroup$

IntegerLength[n] will return the number of digits in an integer.

I could not find a corresponding function that worked for reals, so I wrote my own function, digitsInnumber[n], which works for both integers and reals

enter image description here

Being new to Mathematica, I'd like to know if what I've done is good Mathematica style and if not, is there a better way to do this?

Thanks to the commentators for pointing out various things that I missed. After further thought, I think the following function fixes all the bugs and oversights, except that I couldn't get all fractions to work, so I explicitly eliminated fractions.

digitsInRealOrInteger[x_] := ( 

If[ IntegerQ[x], Return[StringLength[ToString[x]]]]; 

If [Element[x, Rationals] === True,Return[Print["input cannot be a fraction"]]];

If[Element[x, Reals] === True ,Return[StringLength[ToString[x, InputForm]]-1]]; 

Return[Print["input must be real or integer"]]
                              )

I'm surprised that this turned out to be more involved than I originally expected and that I had to resort to a more procedural approach.

$\endgroup$
  • 1
    $\begingroup$ digitsInNumber[1.2+3.4I] returns 10. Is that the intended behavior? $\endgroup$ – evanb Sep 2 '18 at 20:39
  • 3
    $\begingroup$ And, it'd be helpful if you copied your code into your question. Most people won't bother to type your code from a screen shot. $\endgroup$ – evanb Sep 2 '18 at 20:39
  • 1
    $\begingroup$ Similarly, digitsInNumber[3/2] gives 4. $\endgroup$ – evanb Sep 2 '18 at 20:40
  • 1
    $\begingroup$ Using ToString[n, InputForm] will address the precision issue, i.e. StringLength[ToString[0.123456789, InputForm]]-1 will return 10. $\endgroup$ – Lee Sep 2 '18 at 23:57
  • 1
    $\begingroup$ You could try manipulating the output of RealDigits, but there are several cases that need to be handled. RealDigits[23.45] RealDigits[23456] RealDigits[22/7] RealDigits[3/2] RealDigits[0.123456789] RealDigits[0.000123456789] {{2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 2} {{2, 3, 4, 5, 6}, 5} {{3, {1, 4, 2, 8, 5, 7}}, 1} {{1, 5}, 1} {{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0}, 0} {{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0}, -3} $\endgroup$ – Rohit Namjoshi Sep 3 '18 at 3:13
7
$\begingroup$

Inte> IntegerLength[n] will return the number of digits in an integer.

I could not find a corresponding function that worked for reals

It is not very clear what "number of digits" might even mean for reals. For a floating point number, Precision might come closest.

Being new to Mathematica, I'd like to know if what I've done is good Mathematica style and if not, is there a better way to do this?

There are several problems.

In roughly reverse order of seriousness:

  • Return[Print[...]] is incorrect. Print[...] returns Null, while displaying things on screen as a side effect. I assume you did not want to return Null.

  • ToString[x, InputForm] is very very problematic. First, you should have a clear idea of what "number of digits" might even mean, and only start implementing things afterwards. Then you should strive to extract the information you need as directly as possible. Here you convert the number to a representation that is meant to be read by people, not computers, then try to automatically extract information from it anyway. This is what they call a nasty hack. Examples of what can go wrong: (1) InputForm[N[-1/7, 10]] has a -, a . and 10. in it. (2) What if you pass Pi to your function?

    If you were to use a conceptually similar route to this one, a much better way would be to try to extract the "number of digits" from RealDigits, a structured, computer readable representation. Note that this will be the same as Precision. How you could have found this: The IntegerLength doc page as a link to IntegerDigits, which then leads to RealDigits.

  • Be aware of the distinction between mathematical concepts and programming concepts. A real number is a concept in mathematics. A floating point number is a representation of a number in a computer. It's what Mathematica calls a Real. Element/Reals/Integers/Rationals are all for working with math concepts, not programming concepts. Element might not evaluate to either True or False. E.g. 1.0 represents an inexact number in Mathematica, with a precision of ~16 digits ($MachinePrecision). The rest of the digits is unknown. Thus we can't say if it's an integer (the 17th digit may not be zero), and we can't even say if it's a rational. Element won't evaluate for it, which is Mathematica's way of saying "I don't know". In contrast, IntegerQ checks the data type of an expression, not its mathematical meaning. You should validate the function's input in a consistent way, not mix these two concepts. The correct way depends on what you actually want to do, which brings us back to the question: what does "number of digits" mean here?

  • Try to avoid Return for now. While it is useful, everything can be done without it, and beginners typically misuse it (see your use with Print). Do look up Which if you're looking at consecutive Ifs.

  • I understand why you use If[something === True, ...] instead of If[something, ...], but it looks confusing. I recommend If[TrueQ[something], ...] to make your intention clear even to less experienced readers of your code. This is merely a stylistic point.

$\endgroup$
  • $\begingroup$ One definition of "number of digits" might be to look at the minimum number of decimal digits necessary to perform a successful bit-perfect conversion to a Mathematica real at the specific precision. But how useful is this? It's very hard to say, and with naturally imprecise floating point, operations such as (.1 / constant) * constant mess up lower digits of the expression in unexpected ways thanks to the binary base, nature of floating point numbers and the rounding rules involved. $\endgroup$ – kirma Sep 3 '18 at 11:37
  • $\begingroup$ For instance, (.1 / 2) 3 // InputForm is 0.15000000000000002. How many digits does this result have intuitively, and how many from machine perspective? $\endgroup$ – kirma Sep 3 '18 at 11:55
  • $\begingroup$ I agree that ToString[n,InputForm] is a dangerous practice. It goes disastrously wrong in the case of StringLength[ToString[N[Pi,10],InputForm]]. Putting aside the definition of # of digits in a real (e.g. assuming we read fixed #s of digits from a file), what is the best way to count the number of digits present? $\endgroup$ – Lee Sep 3 '18 at 13:44
  • $\begingroup$ @Lee It depends on what you mean by "number of digits". I maintain that the most reasonable way is Precision. If you do not want to count any zeros, you could use RealDigits ... but not counting zeros is not a very well-founded way. How many digits does 100 have? One (because the rest are zeros)? Well, in base 3 it would be written 10201 (no zeros at the end). Why do you choose base 10? If you consider 100 to have 3 digits, then how many does 0.100 have? The only meaningful interpretation I can think of is significant digits, which is basically Precision. $\endgroup$ – Szabolcs Sep 3 '18 at 13:59
  • $\begingroup$ @Szabolcs I agree it depends on what you mean by "number of digits". If what is meant is the number of digits present in the representation of some numbers in a data source, then in that limited case using some form of string conversion would be reasonable. For example if a csv file has the numbers 10.1234 and 0.4500 then saying they have 6 and 5 digits respectively may be appropriate values in the op's context. $\endgroup$ – Lee Sep 3 '18 at 14:39

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.