Asked  6 Months ago    Answers:  5   Viewed   21 times

A colleague of mine stumbled upon a method to floor float numbers using a bitwise or:

var a = 13.6 | 0; //a == 13

We were talking about it and wondering a few things.

  • How does it work? Our theory was that using such an operator casts the number to an integer, thus removing the fractional part
  • Does it have any advantages over doing Math.floor? Maybe it's a bit faster? (pun not intended)
  • Does it have any disadvantages? Maybe it doesn't work in some cases? Clarity is an obvious one, since we had to figure it out, and well, I'm writting this question.

Thanks.

 Answers

24

How does it work? Our theory was that using such an operator casts the number to an integer, thus removing the fractional part

All bitwise operations except unsigned right shift, >>>, work on signed 32-bit integers. So using bitwise operations will convert a float to an integer.

Does it have any advantages over doing Math.floor? Maybe it's a bit faster? (pun not intended)

http://jsperf.com/or-vs-floor/2 seems slightly faster

Does it have any disadvantages? Maybe it doesn't work in some cases? Clarity is an obvious one, since we had to figure it out, and well, I'm writting this question.

  • Will not pass jsLint.
  • 32-bit signed integers only
  • Odd Comparative behavior: Math.floor(NaN) === NaN, while (NaN | 0) === 0
Tuesday, June 1, 2021
 
fillobotto
answered 6 Months ago
80

The problem is that the lowest int is -2147483648, but the highest is 2147483647, so there is no absolute value of -2147483648. While you could work around it, I would just make a special case for that one bit pattern (like you do for 0):

if (x == 0)
    return 0;
if (x == -2147483648)
    return 0xcf000000;

The other problem is that you copied an algorithm that only works for numbers from 0 to 32767. Further down in the article they explain how to expand it to all ints, but it uses operations that you're likely not allowed to use.

I would recommend writing it from scratch based on the algorithm mentioned in your edit. Here's a version in C# that rounds towards 0:

uint float_from_int(int x)
{
    if (x == 0)
        return 0; // 0 is a special case because it has no 1 bits

    // Save the sign bit of the input and take the absolute value of the input.
    uint signBit = 0;
    uint absX = (uint)x;
    if (x < 0)
    {
        signBit = 0x80000000u;
        absX = (uint)-x;
    }

    // Shift the input left until the high order bit is set to form the mantissa.
    // Form the floating exponent by subtracting the number of shifts from 158.
    uint exponent = 158;
    while ((absX & 0x80000000) == 0)
    {
        exponent--;
        absX <<= 1;
    }

    // compute mantissa
    uint mantissa = absX >> 8;

    // Assemble the float from the sign, mantissa, and exponent.
    return signBit | (exponent << 23) | (mantissa & 0x7fffff);
}
Saturday, June 26, 2021
 
Keat
answered 6 Months ago
93

I think what you're looking for is a sequence. A sequence can be either nodes or atomic values (see http://www.w3.org/TR/xslt20/#constructing-sequences).

Here's an example showing the construction of a sequence and then iterating over it. The sequence is the atomic values from @arch, but it could also be nodes.

XML Input

<doc>
    <foo arch="value1;value2;value3"/>
    <foo arch="value1:value4"/>
</doc>

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="archSequence" as="item()*">
        <xsl:for-each select="//@arch">
            <xsl:for-each select="tokenize(.,'[;:]')">
                <xsl:value-of select="."/>                  
            </xsl:for-each>             
        </xsl:for-each>         
    </xsl:variable>

    <xsl:template match="/*">
        <sequence>
            <xsl:for-each select="$archSequence">
                <item><xsl:value-of select="."/></item>
            </xsl:for-each>
        </sequence>
    </xsl:template>

</xsl:stylesheet>

XML Output

<sequence>
   <item>value1</item>
   <item>value2</item>
   <item>value3</item>
   <item>value1</item>
   <item>value4</item>
</sequence>

Example of a sequence of elements (same output):

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:variable name="archSequence" as="element()*">
        <xsl:for-each select="//@arch">
            <xsl:for-each select="tokenize(.,'[;:]')">
                <item><xsl:value-of select="."/></item>         
            </xsl:for-each>             
        </xsl:for-each>         
    </xsl:variable>

    <xsl:template match="/*">
        <sequence>
            <xsl:for-each select="$archSequence">
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </sequence>
    </xsl:template>

</xsl:stylesheet>
Thursday, November 11, 2021
 
josi
answered 3 Weeks ago
98

Alternatively, use a union:

typedef union 
{
    float f_;
    int   i_;
} FloatBits;

FloatBits fb;

fb.f_ = 1.5;

Then fb.i_ contains the float mapped onto an int to allow extraction of the bits. Again, usual assunptions about the size of types - you can verify these using sizeof.

Using this approach, you can play with setting the bits in fb.i_ directly and seeing them mapped back into the float.

Wednesday, November 17, 2021
 
Bitwise
answered 2 Weeks ago
98

If I understand what you're asking, you could do it this way.

Say you have the following HTML markup

<div class='imageholder'>
    <img src='img/1.png' alt=''>
    <div class='watermark'>WATERMARK</div>
</div>

Anything you place in that .watermark div would display in the bottom of the image, overlayed onto it.

Your css would look like this

.imageholder{position:relative;}
.watermark
{
    position:absolute;
    bottom:0;
    background-color:rgba(0,0,0,.4);
}

Having an alpha on the background color would allow the user to partially see through it but still allow your text to be readable.

Friday, November 19, 2021
 
kinske
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share