Panowie... porażka
Jeśli podajecie odpowiedzi to podawajcie chociaż te poprawne :)
Dużo się mówi o tym, aby programiści pisali testy. Nawet na forum się o tym mówi, dlaczego więc Panowie tego nie robicie?
Może dlatego, że przyjdzie ktoś taki jak ja i Was wyręczy :)?
Przejdźmy do wyjaśnienia sprawy:
Najlepszą odpowiedzą w tym wątku było jak na razie:
ilosc_cyfr_w_liczbie_x = trunc(log10(abs(x))+1)
(+specjalny przypadek dla zera)
Z Cóż... absolutnie nie bardzo wierzę w takie "wzorki", bo zazwyczaj mają haczyki. Nie inaczej było w tym przypadku.
Napisałem taki oto kod:
private int GetIloscCyfrWLiczbie(double x)
{
if (x == 0) return 1;
return (int)Math.Truncate(Math.Log10(Math.Abs(x)) + 1);
}
Jest to funkcja na dodatek błędna, gdyż jak autor rozwiązania podał - funkcja potrzebuje specjalnego traktowania dla wartości "0".
Dla liczby 0 wynikiem jest liczba 1.
Co jednak jeśli liczbą będzie "000"? O tym dalej...
oraz funkcję testującą:
private void Test(double x, double result)
{
if (GetIloscCyfrWLiczbie(x) == result)
Console.WriteLine("OK");
else
Console.WriteLine("Błąd");
}
A następnie przypadki testowe: (w komentarzach podane wyniki testów)
Test(1, 1); // ok
Test(12, 2); // ok
Test(-1, 1); // ok
Test(-12, 2); // ok
Test(0, 1); // ok
Test(01, 2); // blad
Test(4294967296, 10); // ok
Test(-4294967296, 10); // ok
Test(111, 3); // ok
Test(-111, 3); // ok
Test(00, 2); // blad
Test(11.1, 3); // blad
Tak jak się spodziewałem. Wzór nie jest poprawny dla pewnych danych szczególnych.
Pierwszy błąd pojawia się w momencie gdy pierwszymi cyframi jest / są zera. Są one wtedy pomijane, zgodnie zresztą z tym jak powinno być. Problem w tym jednak, że w naszym przypadku nie o to nam chodzi i z tego powodu otrzymujemy błędną wartość.
W kolejnym przypadku pojawia się ten sam problem. Tutaj dodatkowo test sprawdzający unikalność cyfr (o tym potem).
Ostatni test, który nie przechodzi poprawnie to jak łatwo się było domyślić - test liczby zmiennoprzecinkowej.
Co, więc należy zrobić? Nic specjalnego. Wystarczy napisać taką oto funkcję:
private int GetIloscCyfrWLiczbie(string x)
{
int result = 0;
for (int i = 0; i < x.Length; i++)
{
if (char.IsNumber(x[i]))
result++;
}
return result;
}
Lekko zmodyfikowany test naszej funkcji:
private void Test(string x, double result)
{
if (GetIloscCyfrWLiczbie(x) == result)
Console.WriteLine("OK");
else
Console.WriteLine("Błąd");
}
oraz przypadki testowe: (w komentarzach podane wyniki)
Test("1", 1); // ok
Test("12", 2); // ok
Test("-1", 1); // ok
Test("-12", 2); // ok
Test("0", 1); // ok
Test("01", 2); // ok
Test("4294967296", 10); // ok
Test("-4294967296", 10); // ok
Test("111", 3); // ok
Test("-111", 3); // ok
Test("00", 2); // ok
Test("11.1", 3); // ok
Jak zrozumiałem zadanie dotyczy "ile jest cyfr w danej liczbie", czyli ile jest łącznie WSZYSTKICH cyfr.
Jeśli jednak źle zrozumiałem zadanie i chodzi o unikalne cyfry, czyli np w liczbie "111", występuje tylko jedna cyfra i jest nią "1",
albo w liczbie "122" występują dwie cyfry 1 i 2 to należy zmodyfikować moją funkcję na taką:
private int GetIloscCyfrWLiczbie(string x)
{
List<int> numbers = new List<int>();
int result = 0;
for (int i = 0; i < x.Length; i++)
{
if (char.IsNumber(x[i]))
{
if (numbers.IndexOf(x.ToString()[i]) == -1)
result++;
}
}
return result;
}
I oto poprawne rozwiązanie problemu :)
Tak się podaje poprawne odpowiedzi panowie :)