[vtk-developers] vtkMath::Ceil() and vtkMath::Floor()

David Gobbi david.gobbi at gmail.com
Thu Jun 2 20:01:06 EDT 2011


HI Philippe,

Of course static_cast<double>(static_cast<int>(x)) is not identity.
It is a truncation operation. There are over a million different double
values that have the same truncated value.  I'm not sure what your
point is regarding that.

In this inequality:

x != static_cast<double>(static_cast<int>(x))

the purpose is to compare the original x (with all its trailing bits)
against the truncation of x (with all the trailing bits removed).

If "x" is exactly equal to trunc(x), and "y" is exactly equal to trunc(x),
then "x" is exactly equal to "y".  If they are even one bit different,
then they cannot both be exactly equal to the same integer.
(excluding the case of +0 and -0 which IEEE 754 guarantees will
be equal when compared to each other, or the case where "x"
or "y" are too large to be represented by int).

I can add comments to the code, but only after this is resolved ;)

 - David



On Thu, Jun 2, 2011 at 5:09 PM, Philippe Pébay <pppebay at sandia.gov> wrote:
> David
>
> Yes, the former. So, what I meant was that we may have, the following
> situation:
>
> * x and y are doubles, different in FP representation (but very close, say
> just above machine epsilon)
> * but yet static_cast<int>( x ) is the same as static_cast<int>( y )
>
> and thus the composition of static_cast<double> with static_cast<int> is not
> the identity. Which may be entirely fine for most cases. But this becomes a
> feature which is worth being documented, since those trailing bits are
> thrown away on purpose as you said.
>
> Now it might very well be that this exactly maps what ceil() and floor() do
> on all platforms, but I am not sure.
>
> Thanks
> Philippe
>
> On 06/02/2011 03:50 PM, David Gobbi wrote:
>>
>> Just a quick follow up: when you say trailing bits, do you mean the
>> trailing bits after those that represent an integer value, or do you
>> mean the bits that might exist beyond the precision of double (i.e.
>> extended precision).  I was assuming the former.
>>
>>  - David
>>
>>
>> On Thu, Jun 2, 2011 at 4:29 PM, David Gobbi<david.gobbi at gmail.com>  wrote:
>>>
>>> Hi Philippe,
>>>
>>> The trailing bits are important in this line:
>>> int g = ( x<  0 );
>>> which compares the original "x" against zero.
>>>
>>> But the static_cast<int>(x) throws away all trailing bits on purpose,
>>> the intent of the double cast is to check whether throwing away the
>>> trailing bits changes the value of the double.
>>>
>>>  - David
>>>
>>>
>>> On Thu, Jun 2, 2011 at 4:22 PM, Philippe Pébay<pppebay at sandia.gov>
>>>  wrote:
>>>>
>>>> Hello David,
>>>>
>>>> Thanks for the explanation. Also, sorry for the typo, I meant "double
>>>> cast"
>>>> (not "double truncation").
>>>>
>>>> My question was with the != comparison between x and
>>>> static_cast<double>(
>>>> static_cast<int>( x ) ).
>>>>
>>>> So, as I understand your answer, the intent is effectively to give a
>>>> definition of what it means
>>>> to be an integer, and in this case, it means that static_cast<double>(
>>>> static_cast<int>( x ) ) is the same as x.
>>>>
>>>> What I don't understand here is what happens to the trailing bits, which
>>>> are
>>>> still significant with respect to machine epsilon. What will happen when
>>>> casting x to int?
>>>>
>>>> Thanks
>>>> Philippe
>>>>
>>>>
>>>> On 06/02/2011 03:01 PM, David Gobbi wrote:
>>>>>
>>>>> Hi Philippe,
>>>>>
>>>>> There is only one truncation, not two.  For Floor() the explanation is:
>>>>>
>>>>> x is input (a double, or maybe extended precision in FPU register)
>>>>>
>>>>> // step 1: truncate to integer
>>>>> int r = static_cast<int>(x);
>>>>>
>>>>> // step 2: check if x can be represented exactly as an int,
>>>>> // put the boolean result "1" or "0" in variable "n"
>>>>> int n = ( x != static_cast<double>(r) );
>>>>>
>>>>> We know that the integer "r" can be represented exactly by
>>>>> a double, and so the above checks if "x" can, in turn, be
>>>>> represented exactly by an int.
>>>>>
>>>>> // step 3: check if x is above/below zero, put the boolean
>>>>> // result "1" or "0" in variable "g"
>>>>> int g = ( x<    0 );
>>>>>
>>>>> // step 4: subtract 1 from the result if steps 2 and 3 are true
>>>>> return r - ( n&    g );
>>>>>
>>>>>
>>>>> The idea behind this is the following: when "x" is>= 0, doing
>>>>> static_cast<int>(x) is exactly the same as floor(x).  But if "x"
>>>>> is less than zero (step 3) we need to subtract one unless "x"
>>>>> can be represented exactly by an int (step 2).
>>>>>
>>>>> The purpose of step 4 is to avoid any branching in the code,
>>>>> as compared to doing the same logic with "if" statements.
>>>>>
>>>>>  - David
>>>>>
>>>>>
>>>>>
>>>>> On Thu, Jun 2, 2011 at 3:25 PM, Philippe Pébay<pppebay at sandia.gov>
>>>>>  wrote:
>>>>>>
>>>>>> Hello David,
>>>>>>
>>>>>> Thanks for the prompt answer.
>>>>>>
>>>>>> I still don't understand the double truncation for Floor() and Ceil():
>>>>>> why
>>>>>> cast the readings to int first, and then to double again? I am not
>>>>>> sure I
>>>>>> understand what "exact results" mean in this contest, as the cast
>>>>>> itself
>>>>>> changes the nature of the representation, and a double cast does not,
>>>>>> as
>>>>>> far
>>>>>> as I know at least, amount to an identity operation.
>>>>>>
>>>>>> Or does it? Are you saying that static_cast<double>( static_cast<int>(
>>>>>> x
>>>>>> ) )
>>>>>> has always the exact same FP representation than x?
>>>>>>
>>>>>> Thanks
>>>>>> Philippe
>>>>>>
>>>>>> On 06/02/2011 02:20 PM, David Gobbi wrote:
>>>>>>>
>>>>>>> Hi Philippe,
>>>>>>>
>>>>>>> I wrote the Floor() and Ceil() functions a few months ago.  They are
>>>>>>> written specifically for speed.  For double values that are within
>>>>>>> the
>>>>>>> int range, they give exact results.
>>>>>>>
>>>>>>> The vtkMath::Round() is fast, too, but the operation that it performs
>>>>>>> does not conform to any of the IEEE 754 standard rounding modes.
>>>>>>>
>>>>>>>  - David
>>>>>>>
>>>>>>> On Thu, Jun 2, 2011 at 3:09 PM, Philippe Pébay<pppebay at sandia.gov>
>>>>>>>  wrote:
>>>>>>>>
>>>>>>>> ... a clarification of what I asked earlier...
>>>>>>>>
>>>>>>>> By "different intent" I was referring to the fact that vtkMath's
>>>>>>>> Floor()
>>>>>>>> and
>>>>>>>> Ceil() perform something which I find a little intriguing, namely,
>>>>>>>> casting a
>>>>>>>> double to an int, and then re-casting the latter to a double to
>>>>>>>> perform
>>>>>>>> a
>>>>>>>> double-double equality comparison, which, I would venture to say,
>>>>>>>> should
>>>>>>>> be
>>>>>>>> avoided whenever possible.
>>>>>>>>
>>>>>>>> On the other hand, Round() does not do this double casting but
>>>>>>>> directly
>>>>>>>> performs double-double inequality comparison, and a single cast to
>>>>>>>> an
>>>>>>>> int
>>>>>>>> at
>>>>>>>> the end. This seems much better to me.
>>>>>>>>
>>>>>>>> Thanks
>>>>>>>> Philippe
>>>>>>>>
>>>>>>>> On 06/02/2011 02:04 PM, Philippe Pébay wrote:
>>>>>>>>>
>>>>>>>>> Hello,
>>>>>>>>>
>>>>>>>>> I was contemplating using vtkMath::Ceil() and vtkMath::Floor() in
>>>>>>>>> some
>>>>>>>>> of my code, instead of the standard ceil() and floor(). However
>>>>>>>>> they
>>>>>>>>> appear to be written with a slightly different intent than
>>>>>>>>> vtkMath::Round(). Can someone comment on that?
>>>>>>>>>
>>>>>>>>> Thanks
>>>>>>>>> Philippe
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Philippe Pébay
>>>>>>>> Sandia National Laboratories
>>>>>>>>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> Powered by www.kitware.com
>>>>>>>>
>>>>>>>> Visit other Kitware open-source projects at
>>>>>>>> http://www.kitware.com/opensource/opensource.html
>>>>>>>>
>>>>>>>> Follow this link to subscribe/unsubscribe:
>>>>>>>> http://www.vtk.org/mailman/listinfo/vtk-developers
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Philippe Pébay
>>>>>> Sandia National Laboratories
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Philippe Pébay
>>>> Sandia National Laboratories
>>>>
>>>>
>>>>
>>>
>>
>
>
> --
> Philippe Pébay
> Sandia National Laboratories
>
>
>



More information about the vtk-developers mailing list