Ao ler o blog do Tiago vi uma solução que ele colocou para encontrar a parte decimal de um número usando C#.

À primeira vista pareceu-me que a solução dele era um pouco ingénua:

   1: public static int GetDecimalPart(double value)
   2: {
   3:     int number = (int) value;
   4:     string numbString = number.ToString();
   5:     int stringLength = numbString.Length;
   6:     return Int32.Parse(value.ToString().Substring(stringLength + 1));
   7: }

Quer dizer, usar strings e Lenght’s? :S Não me parece que seja bom… Então decidi tentar fazer melhor … Esta foi a minha primeira iteração:

   1: public static double GetDecimalPart2(double value)
   2: {
   3:     return value % 1;
   4: }

Ah! Genial, não é? Claro que já tinha um teste unitário à espera:

   1: [Test]
   2: public void CheckSimpleSolution()
   3: {
   4:     Assert.AreEqual(0.02, DecimalTools.GetDecimalPart2(1.02));
   5: }

Infelizmente o resultado não é o esperado:

firsttest

Mas OK. Aqui o problema é que o double, que estamos a usar no GetDecimalPart2 não tem precisão suficiente para estas operações… Basta então tentar assim:

   1: public static double GetDecimalPart2(double value)
   2: {
   3:     return (double)(((decimal)value) % 1);
   4: }

Basta converter o valor para um decimal que, tendo maior precisão, não perde valores na cálculo do ‘% 1′. Como o número original com que estou a trabalhar é um double no final posso voltar a converter para double, sem ter receio de encontrar uma excepção. Correndo o teste:

test2

Excelente… Mas… vendo o código original… o retorno é um inteiro! Isso quer dizer que o valor de retorno de um argumento de 1.02 seria 2, em vez de 0.02. Mas isso também seria o resultado de 1.2… Tenho de ver:

   1: [Test]
   2: public void CheckOriginalForDuplicateResults()
   3: {
   4:     Assert.AreNotEqual(DecimalTools.GetDecimalPart(1.2), DecimalTools.GetDecimalPart(1.02));
   5: }

test3

Ouch… Ao que parece, enganei-me nos requisitos… Pela implementação do Tiago, vejo que ele quer algo completamente diferente. Vejam a seguinte tabela:

Valor Original GetDecimalPart GetDecimalPart2
1.02 2 0.02
1.2 2 0.2
1 0 0.0

 

Apesar do que se pretendido no GetDecimalPart não me fazer sentido, se isso é mesmo o desejado, não me lembro de nenhuma implementação que seja melhor que a do Tiago…

Agora acho que deviam ir ao site dele dizer quanto admiram o código dele e deixarem aqui uns comentários para me dizerem o quanto me odeiam por vos ter feito perder este tempo todo :D