2

Recently I asked the question: Replace byte in a int

and that shows how to replace a byte on an integer. I need to do the same thing with Int64 too. Apparently I am to bad at this lol. I do not know why replacing int to Int64 does not make it work. In other words I modified the solutions on the last question to:

static Int64 ReplaceByte1( int index , Int64 value , byte replaceByte )
{
    return ( value & ~( 0xFF << ( index * 8 ) ) ) | ( replaceByte << ( index * 8 ) );
}

static Int64 ReplaceByte2( int index , Int64 value , byte replaceByte )
{
    // how many bits you should shift replaceByte to bring it "in position"
    var shiftBits = 8 * index;

    // bitwise AND this with value to clear the bits that should become replaceByte
    Int64 mask = ~( 0xff << shiftBits );

    // clear those bits and then set them to whatever replaceByte is
    return value & mask | ( replaceByte << shiftBits );
}

that does not work when using large values. For example calling the method as:

        // returns 12345678848  where it should return 3755744309
        var test1 = ReplaceByte1( 4 , 12345678901 , 0 );

        // returns 12345678848  where it should return 3755744309
        var test2 = ReplaceByte2( 4 , 12345678901 , 0 );

how can I make it work with Int64 too? what am I doing wrong? The only method that works is the last one the slowest one.

Edit

I already made the replacements and I still get different results. Why? take a look:

    // method that words
    static Int64 SlowReplace ( int index , Int64 value , byte replaceByte )
    {
        var bytes = BitConverter.GetBytes( value );
        bytes[ index ] = replaceByte;

        return BitConverter.ToInt64( bytes , 0 );
    }

    static Int64 ReplaceByte1 ( int index , Int64 value , byte replaceByte )
    {
        return ( value & ~( (long)0xFF << ( index * 8 ) ) ) | ( replaceByte << ( index * 8 ) );
    }

    static Int64 ReplaceByte2 ( int index , Int64 value , byte replaceByte )
    {
        // how many bits you should shift replaceByte to bring it "in position"
        var shiftBits = 8 * index;

        // bitwise AND this with value to clear the bits that should become replaceByte
        Int64 mask = ~( ( Int64 )0xff << shiftBits );

        // clear those bits and then set them to whatever replaceByte is
        return value & mask | ( replaceByte << shiftBits );
    }        

    static void Main ( string[ ] args )
    {
        var a = SlowReplace( 4 , 12345678901 , 255 ); //  1098972404789 corect
        var b = ReplaceByte1( 4 , 12345678901 , 255 ); // 3755744511 incorrect
        var c = ReplaceByte2( 4 , 12345678901 , 255 ); // 3755744511 incorrect            

        Console.Read( );            
    }
Community
  • 1
  • 1
Tono Nam
  • 34,064
  • 78
  • 298
  • 470
  • Convert to byte array. Modify index. Convert array to long. System.BitConverter will help – Cole Tobin Oct 31 '12 at 16:31
  • Yeah I know I have that solution on the link http://stackoverflow.com/questions/13161285/replace-byte-in-a-int But note how slow it is compared to the other approaches on the results. – Tono Nam Oct 31 '12 at 16:32

3 Answers3

2

The problem now relies in the replaceByte << shiftBits expression. Refer to the << Operator documentation.

The documentation states that if the first operand is a 32-bit quantity (which in this case it is, because an implicit cast is performed on the byte variable), the shift count is given by the low-order five bits of the second operand. In this case, because shiftBits equals 32 = 2^5, which in binary representation is 100000, the low-order five bits are 00000.

Aside from an explicit cast ((long)0xFF) you can also suffix constants with an l or an L to mark them as long / Int64 (or ul / UL for ulong / UInt64), but 0xFFL can be considered less aesthetic/readable by some. For the replaceByte << shiftBits situation an explicit cast is required.

DoomMuffins
  • 1,174
  • 1
  • 9
  • 19
1

You need to cast the constant 0xff to long:

Int64 mask = ~( (Int64)0xff << shiftBits );

If you don't do this and index is greater than 3 then mask will have the wrong value because the literal 0xff is an int and there is also this rule:

If the first operand is an int or uint (32-bit quantity), the shift count is given by the low-order five bits of the second operand. That is, the actual shift count is 0 to 31 bits.

Since in this case the shift count is a power of two and greater than 31 its low-order five bits will all be zero, which will result in no shift at all (as if shiftBits == 0). So mask will have the wrong value and it will clear the wrong bits out of value, producing a wrong result.

Jon
  • 428,835
  • 81
  • 738
  • 806
0

Replace 0xFF << ( index * 8 ) with (long)0xFF << ( index * 8 )

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179