Skip to main content
Solved

Bit shift gives unexpected result


r_huesken
Contributor
Forum|alt.badge.img+5

Hi,

 

I'm experimenting with bit shifting in FME, and I do not get the expected results. In FME 2020.1.0.1 (see example workbench), (255 << 24) is transformed to a 64 bit integer, and gives me 4278190080.

 

in Postgres database this operation gives the expected result of -16777216. I'm using Postgres as a reference since eventually the results of my FME script will be stored there and used by other applications.

 

I don't understand what I'm doing wrong (or should do to achieve my expected result), and hope somebody can help me out.

 

Thanks,

 

Richard.

 

 

Best answer by david_r

The result you're getting from FME is the correct result for a 64-bit integer (or an unsigned 32-bit integer), also called an arithmetic shift. The result you're getting from Postgres is due to a flipped sign, since the bit shift overflows the signed int32 datatype. This is commonly referred to as a logical shift.

For logical bit manipulations in FME I would recommend using Python, where you can force a specific datatype using the numpy libraries. Example:

>>> import numpy as np
>>> np.int32(255) << 24
-16777216

 To help understand the sign bit, consider the above compared to the same bit shift but using an unsigned 32-bit integer:

>>> np.uint32(255) << 24
4278190080

 

 

View original
Did this help you find an answer to your question?

4 replies

ebygomm
Influencer
Forum|alt.badge.img+32
  • Influencer
  • March 28, 2021

Way outside of my experience, as I've only messed about with bitshifts as part of advent of code but the result you get in FME (4278190080)  is as you would expect given what you are doing is the following

@Evaluate(255*@pow(2,24))

This is above the max for a 32 bit signed integer (you can see this in the error log in your workspace when you try and convert it using @int32)

Attribute(string)                 : `fme_expression_warnings{0}.attributeName' has value `shifted_24_as_int32'
Attribute(string)                 : `fme_expression_warnings{0}.message' has value `Failed to evaluate numeric expression '@int32(4278190080)'.  Result is set to null'
Attribute(string)                 : `fme_expression_warnings{0}.transformerName' has value `AttributeManager'

 

It looks like postgres is handling the overflow by wrapping around. I don't know how you can recreate this in FME. I know in python 255<<24 will give the result as per FME as the integers in python are not of a fixed bit width, you can use numpy to get the result you are seeing in postgres

import fme
import fmeobjects
import numpy as np
 
def processFeature(feature):
    feature.setAttribute("shifted_24_as_int32",int(np.left_shift(255,24)))

 


david_r
Celebrity
  • Best Answer
  • March 29, 2021

The result you're getting from FME is the correct result for a 64-bit integer (or an unsigned 32-bit integer), also called an arithmetic shift. The result you're getting from Postgres is due to a flipped sign, since the bit shift overflows the signed int32 datatype. This is commonly referred to as a logical shift.

For logical bit manipulations in FME I would recommend using Python, where you can force a specific datatype using the numpy libraries. Example:

>>> import numpy as np
>>> np.int32(255) << 24
-16777216

 To help understand the sign bit, consider the above compared to the same bit shift but using an unsigned 32-bit integer:

>>> np.uint32(255) << 24
4278190080

 

 


r_huesken
Contributor
Forum|alt.badge.img+5
  • Author
  • Contributor
  • March 29, 2021
david_r wrote:

The result you're getting from FME is the correct result for a 64-bit integer (or an unsigned 32-bit integer), also called an arithmetic shift. The result you're getting from Postgres is due to a flipped sign, since the bit shift overflows the signed int32 datatype. This is commonly referred to as a logical shift.

For logical bit manipulations in FME I would recommend using Python, where you can force a specific datatype using the numpy libraries. Example:

>>> import numpy as np
>>> np.int32(255) << 24
-16777216

 To help understand the sign bit, consider the above compared to the same bit shift but using an unsigned 32-bit integer:

>>> np.uint32(255) << 24
4278190080

 

 

Hi,

Thanks for the reply. After some experimenting with the PythonCaller, I managed to get the desired result.

 I have uploaded a new version of my workbench, in case somebody might be interested.

 

 


r_huesken
Contributor
Forum|alt.badge.img+5
  • Author
  • Contributor
  • March 29, 2021
ebygomm wrote:

Way outside of my experience, as I've only messed about with bitshifts as part of advent of code but the result you get in FME (4278190080)  is as you would expect given what you are doing is the following

@Evaluate(255*@pow(2,24))

This is above the max for a 32 bit signed integer (you can see this in the error log in your workspace when you try and convert it using @int32)

Attribute(string)                 : `fme_expression_warnings{0}.attributeName' has value `shifted_24_as_int32'
Attribute(string)                 : `fme_expression_warnings{0}.message' has value `Failed to evaluate numeric expression '@int32(4278190080)'.  Result is set to null'
Attribute(string)                 : `fme_expression_warnings{0}.transformerName' has value `AttributeManager'

 

It looks like postgres is handling the overflow by wrapping around. I don't know how you can recreate this in FME. I know in python 255<<24 will give the result as per FME as the integers in python are not of a fixed bit width, you can use numpy to get the result you are seeing in postgres

import fme
import fmeobjects
import numpy as np
 
def processFeature(feature):
    feature.setAttribute("shifted_24_as_int32",int(np.left_shift(255,24)))

 

Thanks. Credits to you too, off course...


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings