0

I'm trying to convert a floating-point number in Python into decimal in C# using pythonnet.

Let's say there is one number 0.0234337688540165776476565071.

I have tried this in two ways:

  1. using float()

    from System import Decimal
    Decimal(0.0234337688540165776476565071)
    # Same with Decimal(float(0.0234337688540165776476565071))
    
    0.02343377
    
  2. using native Python Decimal

    from System import Decimal
    from decimal import Decimal as PyDecimal
    Decimal(PyDecimal("0.0234337688540165776476565071"))
    
    # This loses every number under the floating-point
    0
    

What should I do?

3
  • The value returned from PyDecimal("0.0234337688540165776476565071") is a decimal do why are you putting Decimal() arond the results? If you want more accuracy use Double. A Double is 64 bits while a Float is 32 bits. Decimal gives better accuracy than float with 32 bits for most numbers because it is using a logrithmic algorithm. Double and Float uses exponential algorithm Commented Mar 28, 2021 at 13:36
  • PyDecimal above is native Python type, and I'm trying to convert Python's Decimal into System.Decimal of C#. That's why I did Decimal(PyDecimal(0.212....)). Commented Mar 28, 2021 at 17:58
  • Why would Python Decimal be any dffient from Ne3 Decimal? They both are IEEE 754. See : en.wikipedia.org/wiki/Decimal_floating_point Commented Mar 29, 2021 at 0:28

2 Answers 2

1

From the examples in your question, it looks like you are trying to convert a string to System.Decimal. For that, System.Decimal has a Parse method:

from System import Decimal

Decimal.Parse("0.0234337688540165776476565071")

Note: you probably also need to pass CultureInfo.InvariantCulture depending on your scenario.

Sign up to request clarification or add additional context in comments.

1 Comment

This is really simple and works for me!! Thank you! Why I didn't know this...Parse()
0

If you cast a string to a python float then it will be truncated to 64-bit and you will lose precision. You will have to use a different constructor for System.Decimal. For instance:

public Decimal (int lo, int mid, int hi, bool isNegative, byte scale);

Skipping validation, it might look something like

from System import Decimal
from System import Int32, Boolean, Byte

def str_to_csp_decimal(number: str) -> Decimal:
    """ convert a string to a C# Decimal """
    is_negative = number[0] == "-"
    abs_value = number[1:] if is_negative else number

    has_fraction = "." in abs_value 
    if has_fraction:
        integer, fraction = abs_value.split(".")
        scale = len(fraction)                # denominator = 10 ** scale
        numerator = int(integer + fraction)  # no precision loss for integers
    else:
        scale = 0                            # denominator == 1
        numerator = int(abs_value)
    
    assert numerator < (2 << 96), "Decimal only has 96 bits of precision"

    # split the numerator into the lower, mid, and high 32 bits
    mask = 0xFFFFFFFF
    low = Int32(numerator & mask)
    mid = Int32((numerator >> 32) & mask)
    high = Int32((numerator >> 64) & mask)

    return Decimal(low, mid, high, Boolean(is_negative), Byte(scale))

str_to_csp_decimal("0.0234337688540165776476565071").ToString()

2 Comments

Why not just use Decimal.Parse method?
Your answer is also amazing. Thank you so much for this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.