Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

156
Visualizações
C# decimal (type string) rounded at the last char

This might seem as duplication, but I couldn't find a proper answer (questions were close enough but..) I have a string which represents a decimal number, which always has many decimal places, at least 20, sometimes up to 2000 (represents specific verification calculations, i.e. like 'are digits 135 to 147 prime number X etc. - just to give you some context)

For example:

123.829743892473218762329384241002373824970132871283923423961723816273823447623528347662123874999

I am trying to do roundation to penultimate digit. I built a small method which (kinda) works. BUT (as in the example above).. if the last digit is >4 and penultimate digit is 9 this means that I must raise also the previous digit, and cut the last 0 and if the-then previous number is also 9 that means that I must raise also the previous digit, and so on and so forth.

Ex.

123.99999 // must become 124
123.823467283762378  // must become 123.82346728376238
123.823467283762398  // must become 123.8234672837624 (notice the last 0 has gone)
123.09999999 // must become 123.1 (notice no trailing zeros needed..)
122.00000009 // must become 122.0000001
124.81379281 // must become simply 124.8137928
129.07872345 // must become 129.0787235
129.07872344 // must become 129.0787234

and so on and so forth. In other words, it is just roundation of the number (which is a string!!) by cutting only the last digit, but continue the roundation forward to the left until is not needed. Roundation is needed only for the last decimal place (not if number is integer) and the rule is that if digit at last place is >4 then digit is cut and previous (to the left) digit is being raised by 1, ignoring trailing zero if any, and the rule continues up to the last digit of the integer part (i.e. 123.99999 becomes 124, but integer 124 stays as is etc.).

Could someone help me build a string extension for this?

using System;
    public class Example
    {
        public string round(string LargeDecimal)
        {
            Console.WriteLine("Number as string is: " + LargeDecimal);
            
            int lastDigit = (int)char.GetNumericValue(LargeDecimal[LargeDecimal.Length -1]);   // get last character
            Console.WriteLine("lastDigit = " + lastDigit.ToString());
            
            string number = LargeDecimal.Remove(LargeDecimal.Length - 1);  // delete last character
            Console.WriteLine("Now number is " + number);
            
            if (lastDigit > 4)
            {
                Console.WriteLine("Last digit {0} was >4", lastDigit.ToString());
                int newLastDigit = (int)char.GetNumericValue(number[number.Length -1]);
                Console.WriteLine("Next to left last digit is {0} which will be raised by 1 and become {1}", newLastDigit.ToString(), (newLastDigit +1).ToString());
                newLastDigit += 1;                             //increase by one
                number = number.Remove(number.Length - 1);  // delete ex-penultimate (and now last) character
                number = number + newLastDigit.ToString(); 
                return number;       // and add a digit increased by 1
            }
            else
            {
                return LargeDecimal.Remove(LargeDecimal.Length - 2);
            }
        }
        public Example()
        {}
    }

public class Program
{
    public static void Main(string[] args)
    {
        string myNumber = "124.2398478278268985738276523548769";

        Example myExample = new Example();
    
        string result = myExample.round(myNumber);

        Console.WriteLine("Now I have " + result);
    }
}
over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Here is a solution:

    public static decimal RoundLastChar(this string input)
    {
        decimal inputDecimal = Convert.ToDecimal(input, new CultureInfo("en-US"));
        int decimalPlaces = BitConverter.GetBytes(decimal.GetBits(inputDecimal)[3])[2];
        if (decimalPlaces == 0) return inputDecimal;
        decimal result = Math.Round(inputDecimal, decimalPlaces - 1, MidpointRounding.AwayFromZero).Normalize();
        return result;
    }

    public static decimal Normalize(this decimal value)
    {
        return value / 1.000000000000000000000000000000000m;
    }

The method to get the number of decimal places comes frome here, and the method to Normalize a decimal comes from here.

over 4 years ago · Santiago Trujillo Relatório

0

Because your input value is a string type, I would use decimal.TryParse to make sure the input is valid decimal number.

Then you can try to use a simple algorithm to calculate float Length from your input then do Math.Round

static decimal RoundFirstSignificantDigit(string input) {
    
    decimal significantDigit;
    if (!decimal.TryParse(input,out significantDigit))
    {
        throw new ArgumentException("Invalid input!!");
    }
    var floatLength = input.Split('.')[1].Length;

    return Math.Round(significantDigit, floatLength - 1, MidpointRounding.AwayFromZero);
}

c# online

Edit

if your input with big decimals, due to c# decimal only allow the range between ±1.0 × 10-28 to ±7.9228 × 1028 & didn't support BigDecimal like java currently.

I think there are two ways to do that.

  1. Making your own BigDecimal round logic.
  2. You can try to use IKVM library which supports you to call BigDecimal from java.

You can make your expectation by IKVM simply.

static string RoundFirstSignificantDigit(string input) {
    BigDecimal significantDigit = new BigDecimal(input);
    var floatLength = input.Split('.')[1].Length;
    return significantDigit.setScale(floatLength - 1, BigDecimal.ROUND_HALF_UP).toString().TrimEnd('0');
}

c# online

over 4 years ago · Santiago Trujillo Relatório

0

Well, this is tricky because with 2000 decimal places you can't use decimal. So maybe there's something easier than this, but it might work for you(.NET fiddle demo):

public static string RoundLongNumber(this string input)
{
    if (!ValidLongNumber(input, out bool isInteger) || isInteger) return input;
    int index = input.IndexOf('.');
    string part1 = input.Remove(index);
    string part2 = input.Substring(index + 1);
    StringBuilder sb = new StringBuilder(part2);

    while(true)
    {
        if (LastInt() <= 4)
        {
            return BuildNumber();
        }

        sb.Length = sb.Length - 1; // remove last
        int lastInt = LastInt() + 1;
        while (lastInt == 10)
        {
            sb.Length = sb.Length - 1;
            if (sb.Length == 0)
            {
                // just integer remaining
                int num = int.Parse(part1);
                return (++num).ToString();
            }
            lastInt = LastInt() + 1;
        }

        sb[sb.Length - 1] = (char)(lastInt + '0');
        if (lastInt != 9) return BuildNumber();
    }

    int LastInt() => sb[sb.Length - 1] - '0';
    string BuildNumber() => part1 + "." + sb.ToString();
}

private static bool ValidLongNumber(string number, out bool isInteger)
{
    isInteger = true;
    if (string.IsNullOrWhiteSpace(number)) return false;
    int pointCount = 0;
    foreach(char c in number)
    {
        bool isDigit = char.IsDigit(c);
        bool isPoint = c == '.';
        if (!isDigit) isInteger = false;
        if (isPoint) pointCount++;
        if(pointCount > 1 || (!isPoint && !isDigit)) return false;
    }
    return true;
}

Here's your sample:

public static void Main()
{
    var strings = new List<string> {
    "123.99999", // must become 124
    "129.99999", // must become 130
    "123.823467283762378",  // must become 123.82346728376238
    "123.823467283762398",  // must become 123.8234672837624 (notice the last 0 has gone)
    "123.09999999", // must become 123.1 (notice no trailing zeros needed..)
    "122.00000009", // must become 122.0000001
    "124.81379281", // must become simply 124.8137928 >>> Why? Should remain same
    "129.07872345", // must become 129.0787235
    "129.07872344", // must become 129.0787234        >>> Why? Should remain same
    };

    IEnumerable<string> results = strings.Select(s => s.RoundLongNumber());
    foreach(var res in results)
    {
        Console.WriteLine(res);
    }
}

Note that two results are different, but either you haven't explained that rule or your expectation was wrong:

124.81379281 // must become simply 124.8137928
129.07872344 // must become 129.0787234

Why? For my understanding both should remain same.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda