8
$\begingroup$

I want to get the four corners of a Cuboid. This usually works:

CoordinateBoundingBoxArray[{-{1., 1.}, {1., 1.}}, Into@1]

gives

{{{-1., -1.}, {-1., 1.}}, {{1., -1.}, {1., 1.}}}

as expected.

The expressions CoordinateBoundingBoxArray[{-{1., 0.40}, {1., 0.40}}, Into@1] and CoordinateBoundingBoxArray[{-{1., 0.42}, {1., 0.42}}, Into@1] evaluate to a 2x2 matrix of 2d coordinates as well, as I would expect. But for some reason

CoordinateBoundingBoxArray[{-{1., 0.41}, {1., 0.41}}, Into@1]

gives

{{{-1., -0.41}}, {{1., -0.41}}}

I am confident that this is not the way this should work.

$\endgroup$
11
  • 1
    $\begingroup$ If you're confident, the thing I do is to report it to WRI, not to Mma.SE. $\endgroup$
    – Michael E2
    Commented Jan 15, 2017 at 14:32
  • 1
    $\begingroup$ I am feeling quite ignorant right now; what is Into? $\endgroup$
    – Mr.Wizard
    Commented Jan 15, 2017 at 16:13
  • 1
    $\begingroup$ CoordinateBoundingBoxArray[{min,max},Into[n]] divides into n equal steps in each dimension. reference.wolfram.com/language/ref/… $\endgroup$ Commented Jan 15, 2017 at 16:41
  • 2
    $\begingroup$ @Mr.Wizard. See CoordinateBoundsArray. It is otherwise undocumented AFAIK $\endgroup$
    – m_goldberg
    Commented Jan 15, 2017 at 18:22
  • 1
    $\begingroup$ @J.M. At this point my early senility isn't even an open secret, it's just plain out in the open. I'll keep plugging away until I forget how to sign in or what @@ does. $\endgroup$
    – Mr.Wizard
    Commented Jan 16, 2017 at 4:14

1 Answer 1

9
$\begingroup$

The problem arises from rounding in machine precision. For instance the second-coordinate interval {-0.41, 0.41} leads to this edge case, a one ulp error:

SetAccuracy[1/0.82*0.82, Infinity]
(*  9007199254740991/9007199254740992  *)

It turns out this affects how the range is computed, because Floor is used on it and it returns 0 instead of 1.

One workaround is to avoid machine precision, using either exact numbers or arbitrary precision. Another workaround is to create a Floor that applies a machine-precision fudge factor, in the way that Equal has the fudge factor Internal`$EqualTolerance.

First way:

ClearAll[cbba];
cbba = SetPrecision[
    CoordinateBoundingBoxArray[
     # /. x_?Developer`MachineRealQ :> SetPrecision[x, $MachinePrecision], ##2],
     Precision[#]] &; 

Second way, mostly just as evidence that Floor is implicated:

ClearAll[cbba];
cbba[v_, rest__] /; Precision[v] === MachinePrecision :=
  Internal`InheritedBlock[{Floor},
   Unprotect@Floor;
   Floor[x_] /; ! TrueQ[$in] := Block[{$in = True},   (* Villegas-Gayley *)
     Floor[x + 10^Internal`$EqualTolerance $MachineEpsilon Abs[x]]];
   Protect@Floor;
   CoordinateBoundingBoxArray[v, rest]
   ];

Or even more simply:

ClearAll[cbba];
cbba[args___] /; FreeQ[{args}, Floor] :=
  Block[{Floor = Round},
   CoordinateBoundingBoxArray[args]
   ];

I can't find a way in which this substitution of Round for Floor causes a problem in CoordinateBoundingBoxArray, but I suppose it might.

Test:

cbba[{-{1., 0.41}, {1., 0.41}}, Into@1]
(*  {{{-1., -0.41}, {-1., 0.41}}, {{1., -0.41}, {1., 0.41}}}  *)
$\endgroup$
1
  • $\begingroup$ Awesome research here, thank you! $\endgroup$
    – masterxilo
    Commented Jan 15, 2017 at 21: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.