Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it more efficient to perform a range check by casting to uint instead of checking for negative values?

I stumbled upon this piece of code in .NET's List source code:

// Following trick can reduce the range check by one if ((uint) index >= (uint)_size) {   ThrowHelper.ThrowArgumentOutOfRangeException(); } 

Apparently this is more efficient (?) than if (index < 0 || index >= _size)

I am curious about the rationale behind the trick. Is a single branch instruction really more expensive than two conversions to uint? Or is there some other optimization going on that will make this code faster than an additional numeric comparison?

To address the elephant in the room: yes, this is micro optimization, no I do not intend to use this everywhere in my code – I'm just curious ;)

like image 616
enzi Avatar asked Mar 30 '15 10:03

enzi


People also ask

Should I use int or Uint?

Since we use number with positive and negative integers more often than positive integers only, the type Int is the signed integers. If we want a value without a sign, then we use the type UInt . UInt creates a integer of the same bit size as the device's processor can handle.

What is the difference between Uint and int?

uint means “unsigned integer” while int means “signed integer”. Unsigned integers only contain positive numbers (or zero).

Is Uint smaller than int?

int is shorter to type than uint .

What is an Uint?

A UINT is a 32-bit unsigned integer (range: 0 through 4294967295 decimal). Because a UINT is unsigned, its first bit (Most Significant Bit (MSB)) is not reserved for signing.


1 Answers

From MS Partition I, section 12.1 (Supported data types):

The signed integer types (int8, int16, int32, int64, and native int) and their corresponding unsigned integer types (unsigned int8, unsigned int16, unsigned int32, unsigned int64, and native unsigned int) differ only in how the bits of the integer are interpreted. For those operations in which an unsigned integer is treated differently from a signed integer (e.g., in comparisons or arithmetic with overflow) there are separate instructions for treating an integer as unsigned (e.g., cgt.un and add.ovf.un).

That is, the conversion from an int to a uint is merely a matter of book-keeping - from now on, the value on the stack/in a register is now known to be an unsigned int rather than an int.

So the two conversions should be "free" once the code is JITted, and then the unsigned comparison operation can be performed.

like image 146
Damien_The_Unbeliever Avatar answered Oct 05 '22 23:10

Damien_The_Unbeliever