You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@arrow.apache.org by "Alexey Smirnov (Jira)" <ji...@apache.org> on 2022/07/26 21:03:00 UTC

[jira] [Created] (ARROW-17223) [C#] DecimalArray incorrectly append values greater than Ma

Alexey Smirnov created ARROW-17223:
--------------------------------------

             Summary: [C#] DecimalArray incorrectly append values greater than Ma
                 Key: ARROW-17223
                 URL: https://issues.apache.org/jira/browse/ARROW-17223
             Project: Apache Arrow
          Issue Type: Bug
          Components: C#
            Reporter: Alexey Smirnov


I try to append values into Decimal arrays (Decimal128Array or Decimal256Array), but for values greater than Decimal.MaxValue / 2 and less than Decimal.MinValue / 2, it fails to do it correctly.

For example for DecimalArray128 I created simple unit test:
{code:c#}
[Fact]
public void AppendMaxMinDecimal()                
{
  // Assert
  var builder = new Decimal128Array.Builder(new Decimal128Type(29, 0));
  var max = Decimal.MaxValue;
  var min = Decimal.MinValue; 
 
  // Act
  builder.Append(max);
  builder.Append(min); 

  // Assert
  var array = builder.Build();
  Assert.Equal(max, array.GetValue(0));
  Assert.Equal(min, array.GetValue(1));
}
{code}
I assume it to work correctly, but get:

{color:#de350b}_Assert.Equal() Failure Expected: 79228162514264337593543950335 Actual:   -1_{color}

Looks like the root cause is in _GetBytes_ method of _DecimalUtility_ class:
{code:c#}
//...
Span<byte> bigIntBytes = stackalloc byte[12];

for (int i = 0; i < 3; i++)
{
       int bit = decimalBits[i];
       Span<byte> intBytes = stackalloc byte[4];
       if (!BitConverter.TryWriteBytes(intBytes, bit))
           throw new OverflowException($"Could not extract bytes from int {bit}");

       for (int j = 0; j < 4; j++)
       {
             bigIntBytes[4 * i + j] = intBytes[j];
       }
 }
 bigInt = new BigInteger(bigIntBytes);

//...
{code}
according to MSDN: "The binary representation of a {{Decimal}} value is 128-bits consisting of a 96-bit integer number, and a 32-bit set of flags representing things such as the sign and scaling factor used to specify what portion of it is a decimal fraction".

In 12 bytes BigInteger only 95 bits are used to numbers and 1 bit for a sing.

So code:

{code:c#}
var newBigInt = new BigInteger(Decimal.MaxValue);
var arr = newBigInt.ToByteArray();
{code}

will produce array of 13 bytes long, not 12. 

I tried to change 

_Span<byte> bigIntBytes = stackalloc byte[12];_

to

_Span<byte> bigIntBytes = stackalloc byte[13];_

and this solved the issue.

Should I create a PR for that?



--
This message was sent by Atlassian Jira
(v8.20.10#820010)