Ile cyfr ma liczba

0

Witam,
Mam napisac funkcje ktora bedzie zwracala ilość cyfr danej liczby. Doszedlem tylko do czegos takiego, ze wywali mi cyfre pierwsza.
O to moj kod

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(lol(3));
            Console.ReadLine();
        }
        static int lol(int x)
        {
            int liczba = int.Parse(Console.ReadLine());

            int kolejna_cyfra = 0;
            while (liczba > 0)
            {
                kolejna_cyfra = liczba % 10;
                liczba /= 10;
            }
            return kolejna_cyfra;
            
            
           

        }
    }
}

No niestety potrzebuje wszystkich cyfr podanej liczby. Ktos pomoze? Pozdrawiam

3

Log10

3
 
int liczba = 123454456;
int iloscCyfr = liczba.ToString().Length;
5

Uzupełniając odpowiedź @Marcin.Miga:
ilosc_cyfr_w_liczbie_x = trunc(log10(abs(x))+1)
(+specjalny przypadek dla zera)

0

Jeżeli koniecznie chcesz na piechotę, to realizując Twoją koncepcję, należy zliczać ilość przebiegów pętli while w metodzie lol. Kolejne cyfry otrzymujesz przy każdym przebiegu tej pętli.

0

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 :)

2

gdyż jak autor rozwiązania podał - funkcja potrzebuje specjalnego traktowania dla wartości "0".

Może jestem ślepy, ale gdzie jest tak napisane?

Wzór nie jest poprawny dla pewnych danych szczególnych.

Wzór nie będzie poprawny tylko dla liczb "z przecinkiem"- wtedy należy mnożyć liczbę przez 10, dopóki występuje wartość "po przecinku".

Są one [zera] wtedy pomijane

To nie jest błąd we wzorze - po prostu w matematyce zero to zero, milion zer jest również równe zeru.
00000000000000=0
ilosc_cyfr(00000000000000)=ilosc_cyfr(0)=1

1

Głupoty waść opowiadasz.
Po pierwsze, chodziło (spójrz na pierwszy post) tylko o liczby całkowite.
Po drugie, pytamy o ilość cyfr w liczbie, nie ma liczby 00034, jest liczba 34.
Inna rzecz, że rozwiązanie @Patryk27'a trunc(log10(abs(x))+1) jest poprawne matematycznie, ale niekoniecznie informatycznie. Należałoby sprawdzić jaka (w komputerze) jest wartość log10(10^k): k, trochę więcej niż k, prawie k.

0

Hmmm, ok ale ja chciałem dostosować mój problem do potrzeb ogólnych.
Teraz gdy na forum przyjdzie inny "ktosik" i będzie miał podobny problem, ale już w tym przypadku z liczbami zmiennoprzecinkowymi to Wasz sposób nie zadziała a mój tak. (fakt, że nie doczytałem, że chodziło o cyfry całkowite)

Co do 0034 i innych to faktycznie przesadziłem. Chociaż... sposób do ostry test zawsze jest :)

0

Alternatywne rozwiązanie do powyższych.

public static int LiczbaCyfr( int x )
{
    int digits = 0;

    do
        digits++;
    while((x /= 10) != 0);

    return digits;
}

EDIT: dodam jeszcze krótki komentarz dlaczego w ogóle ten post się pojawił, bo na pierwszy rzut oka wygląda jak musztarda po obiedzie. Otóż uważam za przedstawione przeze mnie rozwiązanie za:

  • krótkie (5 linijek kodu)
  • proste (żadnych odwołań do funkcji)
  • bezawaryjne (działa poprawnie dla każdego int - i to widać na pierwszy rzut oka)

Natomiast korzystając z log10 rzutujemy int -> double i już w tym momencie się zapala lampka ostrzegawcza - nie lubię reprezentacji zmiennoprzecinkowych. Korzystamy z abs(), czyli overflow dla int.MinValue. No i musimy zrobić osobny przypadek dla 0. Log10 jest na pewno lepsze jeśli idzie o wydajność.

1 użytkowników online, w tym zalogowanych: 0, gości: 1