10
$\begingroup$

Is this a bug (happening in V9 and V10 Windows, Linux) or not? It only happens for certain numbers and you need Number in InputField.

maxrange = {0., 70.329862};
InputField[Dynamic@maxrange[[2]], Number]

enter image description here

$\endgroup$
8
  • 1
    $\begingroup$ Seems like it took you some time to arrive at the right digits... ;-) $\endgroup$
    – Yves Klett
    Oct 16, 2014 at 15:00
  • $\begingroup$ Nein nein! This is from a real world project and it is a real number (molar percentage). $\endgroup$ Oct 16, 2014 at 15:11
  • $\begingroup$ Clue?: SetPrecision[70.329862, $MachinePrecision]. (Not sure it's the answer....) $\endgroup$
    – Michael E2
    Oct 16, 2014 at 15:12
  • $\begingroup$ Also, RealDigits[70.329862] gives same behavior. Isn't this just a property of manually-entered floating point numbers, though? The precision depends on how many significant figures you enter in. For example, SetPrecision[70.329862000000000000, $MachinePrecision] gives no errant digits. This is normal behavior if I recall correctly; I'm pretty sure this is explained in the documentation somewhere, although I can't remember which article it's in. $\endgroup$ Oct 16, 2014 at 15:20
  • 5
    $\begingroup$ I do think this is a bug of InputField[ ..., Number] . I really really wish WRI would stop doing anything new for two or three years and just fix all the old bugs... $\endgroup$ Oct 16, 2014 at 15:25

2 Answers 2

17
$\begingroup$

The problem relates to the granularity of MachinePrecision numbers.

The number 70.329862 is represented as an integer times a power of 2:

x0 = SetPrecision[70.329862, Infinity]

(* 4949024067128413/70368744177664 *)

(The denominator is 2^46.) The machine numbers near this number do not allow for the representation of 70.329862 with $MachinePrecision (15.95..) number of digits.

den = Denominator[x0];
N[x0 + Range[-2, 2]/den, $MachinePrecision]
(*
  {70.32986199999998, 70.32986199999999,
   70.32986200000001, 
   70.32986200000002, 70.32986200000003}
*)

The number 70.329862 is closest to its binary machine representative, which can be seen if we display more digits:

N[x0 + Range[-2, 2]/den, 20]
(*
  {70.329861999999977229, 70.329861999999991440,
   70.329862000000005651, 
   70.329862000000019862, 70.329862000000034072}
*)

Now let's consider what the displayed string in the InputField should be. Should it be the 16-digit number closest to the machine number, or should it be the closest simple number? InputField seems to do the first, dropping final zeros. In a numeric sense, it is the most precise representation. For that reason, WRI may feel justified in keeping to the present behavior of InputField. On the other hand, it would be nice if there were an option to InputField to control the display of numbers. I could not find one. If one could set it to display the normal front-end StandardForm, then 70.329862 and 70.3299 would both be displayed as 70.3299. In a sense, one would not know what the input is, only what it is near. In some cases that might be ok.

More than one needs to know

For what it's worth, here is how the behavior comes about. The InputField calls FrontEnd`Private`ToSimpleNumberBoxes to convert the number to a string. It in turn calls NumberForm[val, Infinity, ExponentFunction -> (Null &)]. For a machine precision number val, it will return up to 16 digits, which is how many are needed to distinguish machine reals.

Determined people can redefine FrontEnd`Private`ToSimpleNumberBoxes, which is not Protected. I don't know if that means it is safe to redefine. I would assume it's NOT safe. Be that as it may, the following fixes the toy example InputField. It will display some distinct numbers as if they were the same because it shows a number of digits that is less than the precision. And it will affect all input fields. Thus I would say this is not a solution, at least not a good one. It does suggest that no easy fix is likely to be found.

FrontEnd`Private`ToSimpleNumberBoxes[FrontEnd`Private`value_?NumberQ, StandardForm] := 
 ToString[NumberForm[FrontEnd`Private`value, 
   Floor[Precision[FrontEnd`Private`value]],
   ExponentFunction -> (Null &)]]

For everyday use

Instead of messing with system functions, one can control the behavior of InputField within Dynamic:

InputField[
 Dynamic[ToString[
   NumberForm[maxrange[[2]], Floor[Precision[maxrange[[2]]]], 
    ExponentFunction -> (Null &)]], 
  If[StringMatchQ[#, FrontEnd`Private`ValidNumberRegex], 
    maxrange[[2]] = ToExpression[#]] &],
 String]

Then one can really control the input and output formatting as desired. (I don't believe this will work with restricted CDFs, though.)

$\endgroup$
4
  • $\begingroup$ Great! This is just perfect for everyday use! $\endgroup$ Oct 16, 2014 at 19:54
  • $\begingroup$ @RolfMertig I added another workaround. $\endgroup$
    – Michael E2
    Oct 16, 2014 at 20:31
  • $\begingroup$ I prefer Number as second argument of InputField rather than String. This way users really only can enter numbers. If I put your FrontEndPrivateToSimpleNumberBoxes definition into the Initialization of the DynamicModule things just work in PlayerPro 9.0.1 (still no PlayerPro 10, unfortunately. But I am sure we will enjoy it soon). $\endgroup$ Oct 16, 2014 at 22:35
  • $\begingroup$ @RolfMertig The way the Dynamic in the InputField is set up, an edit is accepted only if the input string matches FrontEnd`Private`ValidNumberRegex (the same as Number in the second argument), although the user may enter any characters. I understand the difference might be unsatisfactory. The main thing to beware is that I do not know what front-end functions depend on ToSimpleNumberBoxes. (As it is an output formatting function, it might not matter that much.) $\endgroup$
    – Michael E2
    Oct 17, 2014 at 1:40
10
$\begingroup$

EDIT

Input gets different rounding to machine-precision real if it's written in arbitrary precision!

RealDigits[70.329862, 2]

(* {{1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0,
     0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 
     1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1}, 7} *)

RealDigits[
 SetPrecision[70.329862000000000000, $MachinePrecision], 2]

(* {{1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0,
     0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 
     1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0}, 7} *)

Precise expansion would indicate that without using four bits of extra precision, both are 0.5 ulp off:

Flatten@RealDigits[70329862/1000000, 2]~Take~57

(* {1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0,
    0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1,
    1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1} *)

In this case, the form without arbitrary precision is closer to the true value, but that rounding up pushes the trailing 1 into the decimal back-conversion.

Original answer:

In Mathematica, MachinePrecision reals are represented as double-precision (53 bit mantissa) binary floating point numbers. The critical point here is not so much "floating point", but "binary."

Consider the following:

RealDigits[0.1, 2, 53]

(* {{1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0,
     0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1,
     0, 0, 1, 1, 0, 1, 0}, -3} *)

Since 1/10 is not representable with sum of finite amount of integer powers of two, this floating point representation is actually only approximate!

There are heuristics in conversion of binary representation to sufficiently precise decimal notation. Occasionally selection of these heuristics causes rounding on lowest bits of binary representation to creep up the way you see it now. For instance, do you want output "decimal-looking" numbers to be pretty, or to get faithfully rounded transcendentals, or rationals expanded to correct recurring forms? There's no single easy answer.

You may also ask: why not use absolutely precise conversion from binary to decimal representation? Well, it has its' drawbacks. Consider precise decimal expansion of MachinePrecision 0.1:

N[FromDigits[First@RealDigits[0.1, 2, 53], 2]/2^56, 60]

(* 0.100000000000000005551115123125782702118158340454101562500000 *)

(Only some of those digits are necessary to precisely represent the binary floating-point value. As @MichaelE2 shows, there are intervals on which all values are valid representations; what to pick?)

$\endgroup$
4
  • $\begingroup$ You just beat me by a couple of minutes! :) Well, I guess I'm saying some things that are different at least. I guess I don't need to delete? $\endgroup$
    – Michael E2
    Oct 16, 2014 at 16:00
  • $\begingroup$ @MichaelE2 I hope these answers complement each other. :) $\endgroup$
    – kirma
    Oct 16, 2014 at 16:12
  • $\begingroup$ @kirma: very nice analysis. But I am going to accept Michael E2's answer because it provides a fix ( the greatest thing of M is that knowledgable users can fix bugs way ahead of WRI). $\endgroup$ Oct 16, 2014 at 22:37
  • $\begingroup$ @RolfMertig No problem. :) $\endgroup$
    – kirma
    Oct 17, 2014 at 4:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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