6
$\begingroup$

I was trying to convert some arbitrary-precision numbers to machine-precision numbers using N[myNumber,MachinePrecision]. But, although my test number did lose some precision, it still had a very strange exponent:

number = 5.803736411761291186334053015446685`16*^-400;
number1 = SetPrecision[number, MachinePrecision]

5.803736411761291×10^-400

As $10^{-400}$ is not representable in IEEE 754 binary64, and I'm on x86 where this format is native, I tried checking what precision the number has, and it appears

Precision@number1

15.954589770191

This might be OK if truly machine-precision numbers gave the same, but they don't:

[email protected]

MachinePrecision

Finally, I've checked my number given by SetPrecision using FullForm:

FullForm@number1

5.803736411761291186334053015446685`15.954589770191005*^-400

So, apparently, SetPrecision won't give me machine number. How then do I convert my arbitrary-precision number to machine number? (I'd expect the $~10^{-400}$ value to be rounded down to machine zero.)

$\endgroup$
3
  • 2
    $\begingroup$ N[number]?? From Documentation Center page "MachinePrecision": "MachinePrecision is the symbol representing the number of decimal digits used by numerical functions such as N, NIntegrate, and NSum in the Wolfram Language for machine-precision computations." $\endgroup$
    – murray
    Nov 30, 2017 at 22:03
  • 1
    $\begingroup$ @murray have you actually tried it? Its result is not different from that from SetPrecision[number,MachinePrecision]. $\endgroup$
    – Ruslan
    Dec 1, 2017 at 6:02
  • $\begingroup$ Related: (37764) $\endgroup$
    – Mr.Wizard
    Jul 24, 2018 at 4:47

4 Answers 4

8
$\begingroup$

This situation is comparable to

$MinMachineNumber / 2

automatically giving an arbitrary precision result.

Precision[$MinMachineNumber/2]
(* 15.9546 *)

Mathematica detects the underflow condition and switches to arbitrary precision arithmetic. This can be turned off:

SetSystemOptions["CatchMachineUnderflow" -> False]

Now the result of $MinMachineNumber/2 has MachinePrecision. The result is not 0., but a denormal number, I believe (my knowledge is lacking in this area). If you divide by a number larger than 10^$MachinePrecision then you get a 0..

$MinMachineNumber/2
(* 1.11254*10^-308 *)

$MinMachineNumber/10^15
(* 2.5*10^-323 *)

$MinMachineNumber/10^16
(* 0. *)

SetPrecision works as you want it, too.

number = 5.803736411761291186334053015446685`16*^-400;
number1 = SetPrecision[number, MachinePrecision]
(* 0. *)

SetPrecision will not create denormal numbers, it seems.

SetPrecision[1.2`16*^-308, MachinePrecision]
(* 0. *)
$\endgroup$
4
  • $\begingroup$ With V11.1.1 running on OS X 10.10.2, I do not get the OP's result from SetPrecision, not yours. $\endgroup$
    – m_goldberg
    Dec 1, 2017 at 6:06
  • $\begingroup$ Wow never supposed Mathematica would use allow denormals (they are performance killers for machine-precision computations). Is there any way to enable Flush-To-Zero mode in Mathematica (other than attaching a debugger and change MXCSR manually :) )? $\endgroup$
    – Ruslan
    Dec 1, 2017 at 6:14
  • $\begingroup$ @m_goldberg Sorry, I do not understand. What do you get precisely when underflow checking is enabled/disabled? $\endgroup$
    – Szabolcs
    Dec 1, 2017 at 7:13
  • $\begingroup$ I did not read your post carefully enough to realize the results you showed applied to the case where catching machine overflow had been turned off. $\endgroup$
    – m_goldberg
    Dec 2, 2017 at 0:18
7
$\begingroup$
number = 5.803736411761291186334053015446685`16*^-400;
number + 0.
(* 0. *)

N makes arbitrary precision numbers when either given a second argument or a number not representable by a machine number as its first argument. However, machine numbers in expressions generally coerce arithmetic into the machine domain.

$\endgroup$
3
$\begingroup$

Another way:

toMPReal = Compile[x, x][#] &(*/.c_Compile :> RuleCondition[c]*);

toMPReal[5.803736411761291186334053015446685`16*^-400]
(*  0.  *)

Uncomment the replacement rule to pre-compile the function.

$\endgroup$
3
$\begingroup$

Starting in M11.3, SetPrecision will always produce a machine number when the second argument is MachinePrecision. The documentation for SetPrecision was unfortunately not updated with this change. Also, this means that the system option SetSystemOptions["CatchMachineUnderflow" -> True] no longer does anything. So, now you get the desired behavior without modifying any system options:

number = 5.803736411761291186334053015446685`16*^-400;
number1 = SetPrecision[number,MachinePrecision]

0.

$\endgroup$

Your Answer

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

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