5
$\begingroup$

How can I quickly convert a number with $n$ decimal points to a number of with $m$ decimal points? Round works, however, it is slower than I would like. This example rounds a set of $100$ real numbers to $0.1$ decimal precision:

testvalues = Table[{RandomReal[], RandomReal[]}, {i, 1, 100}]

t1 = AbsoluteTime[];

For[i = 1, i <= 10^5, i++,
  Round[testvalues, 0.1];
];

t2 = AbsoluteTime[];

t2 - t1

Takes $\approx 11.87$ seconds on my 3.47 GHz CPU. Floor and Ceiling take a commensurate amount of time.

$\endgroup$
7
  • $\begingroup$ User, what version of Mathematica are you using? I am using version 7 and get timings that are within an order of yours. Another user reports timings that are an order of magnitude faster. $\endgroup$
    – Mr.Wizard
    Sep 19, 2013 at 6:13
  • $\begingroup$ @Mr.Wizard I am using version 9.0.1.0 on a 64-bit operating system. $\endgroup$
    – RM1618
    Sep 19, 2013 at 6:16
  • $\begingroup$ User, please try the code in my answer and report your timings after packing; I believe you may get a much larger improvement than I did. $\endgroup$
    – Mr.Wizard
    Sep 19, 2013 at 6:32
  • $\begingroup$ Evaluating SeedRandom[42]; testvalues = RandomReal[1., {100, 2}]; For[i = 1, i <= 100000, i++, Round[testvalues, 0.1]]// AbsoluteTiming on my system gives {0.713849, Null} which is way faster than what the OP is seeing. I'm using V.9.0.1 on OS X 10.6.8 on a three year old iMac with a 2.93 MHz i7 iMac. I am very puzzled by the discrepancy. $\endgroup$
    – m_goldberg
    Sep 19, 2013 at 6:40
  • 2
    $\begingroup$ @Mr.Wizard I ran your code for Packing: unpacked values gives {11.361650, Null} and packed values gives {0.640037, Null}. Hmmm.... $\endgroup$
    – RM1618
    Sep 19, 2013 at 6:50

2 Answers 2

4
$\begingroup$

Packing

You should make sure that your data is packed if at all possible:

Developer`PackedArrayQ[testvalues]
False
packedvalues = Developer`ToPackedArray@testvalues;

This at least speeds things a bit (timings in version 7 under Windows):

Do[Round[testvalues, 0.1], {10^5}]   // AbsoluteTiming
Do[Round[packedvalues, 0.1], {10^5}] // AbsoluteTiming
{7.0500098, Null}

{6.0500085, Null}

In version 9, and possibly 8, you should see a much greater improvement from packing that I experienced here in version 7. Other users are reporting well over an order of magnitude improvement in later versions.

Note that if you had generated the values with RandomReal[1, {100, 2}] they would have been packed to start with.

Data shape

In version 7, where the Round operation is handled by the Mathematica Kernel rather than the Intel MKL transposing the values before rounding makes a considerable difference:

Do[Round[packedvalues\[Transpose], 0.1]\[Transpose], {10^5}] // AbsoluteTiming
{3.8900054, Null}

SetAccuracy

Also applicable to version 7, an alternative that may be acceptable it is to use SetAccuracy which on my system this about twice as fast:

tvalues = packedvalues\[Transpose];

Do[SetAccuracy[tvalues, 2], {10^5}] // AbsoluteTiming
{1.7961027, Null}

Note that users of more recent versions will find that Round on a packed array is faster than SetAccuracy.

$\endgroup$
14
  • $\begingroup$ I have {11.361650, Null} for unpacked values and {0.640037, Null} for packed values. Why am I seeing an order of magnitude speedup relative to you? $\endgroup$
    – RM1618
    Sep 19, 2013 at 6:51
  • $\begingroup$ Data Shape: I get {0.876050, Null}. $\endgroup$
    – RM1618
    Sep 19, 2013 at 6:52
  • $\begingroup$ SetAccuracy: I get {2.585148, Null}, similar to your numbers. $\endgroup$
    – RM1618
    Sep 19, 2013 at 6:52
  • $\begingroup$ It looks like Packing solves my speed issue, but the lesson is that this only works in v9? $\endgroup$
    – RM1618
    Sep 19, 2013 at 6:53
  • 1
    $\begingroup$ @george2079 My point is that the numbers should have been packed on generation or at least before further operations, therefore no, I do not believe it should have been included in the loop. $\endgroup$
    – Mr.Wizard
    Sep 19, 2013 at 18:39
0
$\begingroup$

For this example I get a 4-fold speed increase using Map:

 Round[testvalues, .1]

(* ~12 sec *)

 Map[Round[#, .1] &, testvalues, {2}]

(* ~3 sec *)

Edit, note if we do this with packedarrays the direct round applicaiton wins..

 Map[Round[#, .1] &, packedvalues, {2}]

(* 3 sec *)

Round[packedvalues, .1]

(* 0.9 sec *)

If you include the packing operation in the timing its still pretty good..

Round[(Developer`ToPackedArray@testvalues), .1]

(1.3 sec)

... All timing with the For loop in the original Question ...

$\endgroup$
1
  • $\begingroup$ What testvalues are you using? Surely not the 100x2 array with those timings. $\endgroup$
    – Mr.Wizard
    Sep 21, 2013 at 0:20

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.