4
$\begingroup$

I am trying to format the timing reported by AbsoluteTiming so that it states the hours minutes and seconds of the result. However, probably because AbsoluteTiming has the attribute HoldAll, the results are not entirely as I would expect them.

I define the two related functions:

secondsToHoursMinutes[secs_] := Module[{
   hrs = Floor[secs/3600],
   mins = Floor[Mod[secs, 3600]/60],
   scs = Mod[secs, 60]},
  If[hrs == 0, "0", ToString[hrs]] <> ":" <> 
   Which[mins == 0, "00", mins < 10, "0" <> ToString[mins], True, 
    ToString[mins]] <> ":" <> 
   Which[scs == 0, "00", scs < 10, "0" <> ToString[scs], True, 
    ToString[scs]]]
absTimingInHoursMinutes[
  operation_] := (({secondsToHoursMinutes[#[[1]]], #[[2]]}) &[
   AbsoluteTiming[operation]])

However, the results of the following are different. I have tried putting Evaluate@ and ReleaseHold@ inside or around AbsoluteTiming to no avail. Any ideas?

Table[i, {10^6}]; // AbsoluteTiming
absTimingInHoursMinutes[Table[i, {10^6}];]
Table[i, {10^6}]; // absTimingInHoursMinutes
Table[i, {10^6}]; // 
  AbsoluteTiming // {secondsToHoursMinutes[#[[1]]], #[[2]]} &
{secondsToHoursMinutes[#[[1]]], #[[2]]} &[
 AbsoluteTiming[Table[i, {10^6}];]]
$\endgroup$

2 Answers 2

4
$\begingroup$

I have these in my kernel init file, my main use case is not wanting to count how many zeroes are in the AbsoluteTiming result. Is that milliseconds or microseconds? I added the MixedUnit part here to cover OP's use case. Hopefully it is useful to someone else.

bestUnit[unitLog_] := Which[
    unitLog < -6,
        "Nanoseconds",
    unitLog < -3,
        "Microseconds",
    unitLog < 0,
        "Milliseconds",
    unitLog < 1.77815(*Log10[60.]*),
        "Seconds",
    unitLog < 3.5563(*Log10[60. * 60.]*),
        MixedUnit[{"Minutes", "Seconds"}],
    True,
        MixedUnit[{"Hours", "Minutes", "Seconds"}]
];

fixTime[{t_, res_}] = {
    UnitConvert[Quantity[t, "Seconds"], bestUnit @ Log10 @ t],
    res
};
repeatedTiming[arg__] := fixTime @ RepeatedTiming @ arg;
absoluteTiming[arg__] := fixTime @ AbsoluteTiming @ arg;
Attributes[repeatedTiming] = Attributes @ RepeatedTiming
Attributes[absoluteTiming] = Attributes @ AbsoluteTiming

And then use as

In[4]:= repeatedTiming[Exp[Range[500]];]

Out[4]= {Quantity[197.414, "Microseconds"], Null}
$\endgroup$
1
  • $\begingroup$ Ya, I am running a Markov-Chain-Monte-Carlo model of a very complex system, where taking many runs to get the precise shape of the underlying distributions can take hours. $\endgroup$
    – Nicholas G
    Apr 26, 2022 at 13:09
7
$\begingroup$

I think you need to add the HoldFirst attribute to your timing function, like this

SetAttributes[absTimingInHoursMinutes, HoldFirst]

Here is my take on a similar function that formats the AbsoluteTiming results using the built-in Units & Quantities system. Without the HoldFirst (or HoldAll) attribute, this function would not work.

ClearAll[absTiming]
SetAttributes[absTiming, HoldFirst]
absTiming[op_] := op // AbsoluteTiming // {UnitConvert[
     Quantity[First[#], "Seconds"],
     MixedUnit[{"Hours", "Minutes", "Seconds"}]], Last[#]} &

SeedRandom[1234]
Eigensystem[RandomInteger[{-100, 100}, {14, 14}]]; // absTiming

(*  {0 h 0 min 4.8642s, Null}  *)
$\endgroup$
2
  • $\begingroup$ Many thanks! Did you intend to have the first word of your answer's third paragraph ("Here") link something? $\endgroup$
    – Nicholas G
    Apr 22, 2022 at 14:27
  • $\begingroup$ @NicholasG That is good intuition, but, no, I did not intend to link to somewhere else. I meant "here" as "in this answer". BTW, thanks for accepting my answer. $\endgroup$
    – LouisB
    Apr 22, 2022 at 19:21

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.