开发者

Converting C++ Bit Pattern to Java

I am converting a C++ program to Java and got completely stuck in the following method which blew my mind. Would you be kind enough to explain what this method is doing?

long TSBCA::GetSignedValue(const NDataString &value)
    {
       static NDataString s;    
       s = value;

       long multiplier(1);
       size_t len(s.Len());
       if (len != 0)
       {
          if (s[0] >= (char)0xB0 && s[0] <= (char)0xB9)
          {
             s[0] &= 0x7F; //Bit Pattern: 0111 1111
             multiplier = -1;
          }
          else if (s[len - 1] >= (char)0xB0 && s[len - 1] <= (char)0xB9)
          {
             s[len - 1] &= 0x7F; //Bit Pattern: 0111 1111
             multiplier = -1;
          }
          else
             multiplier = 1;
       }
       else
          multiplier = 1;
       return s.ToLong() * multiplier;
    }

EDIT:

My initial Java version:

private long getSignedValue(final String value){

       byte[] bytes = value.getBytes();
       int length = bytes.length;
       long multiplier = 1L;

       if (bytes.length > 0)开发者_C百科{
          if (bytes[0] >= (char)0xB0 && bytes[0] <= (char)0xB9){


             bytes[0] &= 0x7F; //Bit Pattern: 0111 1111
             multiplier = -1;
          }
          else if (bytes[length - 1] >= (char)0xB0 && bytes[length - 1] <= (char)0xB9)
          {
              bytes[length - 1] &= 0x7F; //Bit Pattern: 0111 1111
             multiplier = -1;
          }
          else
             multiplier = 1;
       }
       else
          multiplier = 1;
       return Long.parseLong(Arrays.toString(bytes))* multiplier;
}

Did I do it right?


It's taking a byte string (i.e. not text) and converting to it a long. It relies on many implementation specific things, and appears broken: it's extracting the sign bit from two different places. Another issue is the needless non-reentrancy (caused by the static variable).


s[0] &= 0x7F;

means bit-and s[0] with hex 7F or in other words, strip the sign bit off the byte value. same with s[len-1], so it:

  • takes a numerical string, where the first or the last digit has a sign bit added (0x30 - 0x39 == '0' - '9' and 0xB0 - 0xB9 is the same range with the 0x80 bit set.)
  • strips that sign bit, remembering it as multiplier
  • interprets the numerical string argument using the multiplier to set the sign
  • returns that value

Edit:

Reviewing your code leads me to the following remarks:

  • it does not work as intended, be sure to write some JUnit tests for new code to check that they do what you expect
  • place the magic numbers in separate constants
  • use byte constants when comparing to bytes (sign issues)
  • the dangling else's should get braces and in this case are unneeded
  • use new String(byte[]) to reconstruct the string, not the Arrays utility class.

This leads me to this version:

// Bit Pattern: 0111 1111
private static final int BYTE_7F = 0x7F;

// '0' with sign bit set
private static final byte BYTE_NEGATIVE_0 = (byte) 0xB0;

// '9' with sign bit set
private static final byte BYTE_NEGATIVE_9 = (byte) 0xB9;


private long getSignedValue(String value) {

    byte[] bytes = value.getBytes();
    final int length = bytes.length;
    long multiplier = 1;

    if (0 < length) {
        if (bytes[0] >= BYTE_NEGATIVE_0 && bytes[0] <= BYTE_NEGATIVE_9) {

            bytes[0] &= BYTE_7F; 
            multiplier = -1;

        } else if (bytes[length - 1] >= BYTE_NEGATIVE_0 && bytes[length - 1] <= BYTE_NEGATIVE_9) {
            bytes[length - 1] &= BYTE_7F;
            multiplier = -1;
        }
    }

    return Long.parseLong(new String(bytes)) * multiplier;
}

You still have to pay attention to adding correct comments and update the constant names to bring them in line with your documentation terminology.


Looks like it's testing for some weird version of sign (positive or negative). If the first or last (but preferably first) character is between 0xB0 and 0xB9, then hack off the highest order bit of whichever character it was (making it between 0x30 and 0x39, the digits '0' through '9'). Then return the number with a negative sign as normal humans know it.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜