Dokładność typów double i decimal

0

Pytanie pewnie jedno z prostszych, otóż napisałem prosty program konsolowy do wyliczania jakie nominały ekspedientka powinna wydać w zależności od reszty. Wszystko na ifach, nominały poszeregowane od największego nominału do najmniejszego (500 zł do 1 grosz) po wydaniu zmienna double money zmniejszała się odpowiednio. Problem jest w chwili gdy program powinien wydać jeden grosz a zmienna money jest w tym momencie mniejsza od niego (nie wiem dlaczego). Chodzi tu o błędy w zapisie liczb w komputerze? Zawsze mi się wydawało, że takie błędy występują przy dosyć małych liczbach a nie 0,01. Użyłem również zmiennej decimal, która okazała się jeszcze mniej dokładna niż double. Wytłumaczy ktoś o co chodzi?

1

Pokaż kod.

0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Program
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Podaj ile reszty kasjerka ma wyplacic \n");
            double money = double.Parse(Console.ReadLine());
            while(money!=0)
            {
                if(money > 500)
                {
                    Console.WriteLine("Wydano 500 zlotych\n");
                    money -= 500;
                    continue;
                }
                if(money > 200)
                {
                    Console.WriteLine("Wydano 200 zlotych\n");
                    money -= 200;
                    continue;
                }
                if(money >100)
                {
                    Console.WriteLine("Wydano 100 zlotych\n");
                    money -= 100;
                    continue;
                }
                if (money > 50)
                {
                    Console.WriteLine("Wydano 50 zlotych\n");
                    money -= 50;
                    continue;
                }
                if (money >20)
                {
                    Console.WriteLine("Wydano 20 zlotych\n");
                    money -= 20;
                    continue;
                }
                if (money > 10)
                {
                    Console.WriteLine("Wydano 10 zlotych\n");
                    money -= 10;
                    continue; 
                }
                if (money > 5)
                {
                    Console.WriteLine("Wydano 5 zlotych\n");
                    money -= 5;
                    continue;
                }
                if (money > 2)
                {
                    Console.WriteLine("Wydano 2 zlote \n");
                    money -= 2;
                    continue;
                }
                if (money >1)
                {
                    Console.WriteLine("Wydano 1 zloty\n");
                    money -= 1;
                    continue;
                }
                if (money > 0.5)
                {
                    Console.WriteLine("Wydano 50 groszy \n");
                    money -= 0.5;
                    continue;
                }
                if (money > 0.2)
                {
                    Console.WriteLine("Wydano 20 groszy \n");
                    money -= 0.2;
                    continue;
                }
                if (money > 0.1)
                {
                    Console.WriteLine("Wydano 10 groszy \n");
                    money -= 0.1;
                    continue;
                }
                if (money > 0.05)
                {
                    Console.WriteLine("Wydano 5 grosze \n");
                    money -= 0.05;
                    continue;
                }
                if (money > 0.02)
                {
                    Console.WriteLine("Wydano 2 grosze \n");
                    money -= 0.02;
                    continue;
                }
                if (money > 0.01)
                {
                    Console.WriteLine("Wydano 1 grosz \n");
                    money -= 0.01;
                    continue;
                }
            }
        }
    }
}
3

Jak ma wydać ostatni grosz, jeżeli if sprawdza czy > niż 1 grosz, a nie >=?

PS: Jeżeli masz dużo powtarzającego kodu, gdzie np. zmienia się tylko jedna rzecz, to zazwyczaj da się go napisać sprytniej ;)

0
WeiXiao napisał(a):

Jak ma wydać ostatni grosz, jeżeli if sprawdza czy > niż 1 grosz, a nie >=?

racja, nie pomyślałem

0

Po kiego grzyba używasz typu double zamiast decimal ?
Tłumaczone było już milion razy że typ double nie nadaje się do obliczeń finansowych .

0
Zimny Krawiec napisał(a):

Po kiego grzyba używasz typu double zamiast decimal ?
Tłumaczone było już milion razy że typ double nie nadaje się do obliczeń finansowych .

Na początku miałem decimal, ale ze względu na to że przy 1groszu nie miałem większy lub równy to wychodziły podobne głupoty co w double

1

Używaj groszy w obliczeniach, a przy wyświetlaniu jedynie dziel przez sto. Używając typu zmiennoprzecinkowego do obliczeń pieniężnych prędzej czy później dostaniesz kopa.

1

Sam program da się skrócić, pozbywając się ifów:

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

namespace CSharpConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var nominals = new List<int>
            { 50000, 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1 };

            int money = 150; // 1,50zł.

            while (money != 0)
            {
                var n = nominals.First(m => money >= m);
                Console.WriteLine(n / 100.0);
                money -= n;
            }
        }
    }
}

0

Linq znam, ale jak widać jeszcze nie mam automatyzmu w korzystaniu z niego. Przykład Grześka bardzo pomocny

2

Witam,

var banknotes = new decimal[] {50,20,10,5,2,1,0.5m,0.2m,0.1m,0.05m,0.02m,0.01m};
var value = 2356.96m;

for (var i = 0; i < banknotes.Length; i++)
{
	while (value >= banknotes[i])
	{
		Console.WriteLine(banknotes[i]);
		value -= banknotes[i];
	}
}

Wersja bez LINQ dla nominałów z UK

Pozdrawiam,

mr-owl

0

Jeszcze takie pytanie, gdyby tych nominałów było więcej (bardzo dużo) to pod względem szybkości programu lepiej używać tablic czy list?

2

Jeżeli ich liczba jest stała, to tablic. Lista to jest tak na prawdę dynamicznie zmieniana tablica pod spodem, więc ma sens tylko gdy nie znasz z góry liczby elementów.

1

Ja bym użył tablicy, ale nie ze względu na szybkość, lecz dlatego, że niepotrzebna jest możliwośc dynamicznej edycji, którą daje lista.

0

Nie ma sensu używać tablic w (100% - kilka) przypadkach.

3

Kod jest błędny (Mowa o autorskim). Prześledż sobie jak rozpisze 1000zł, zamiast dwie 500ki będzie to ciąg wszystkich nominałów (w jednym obiegu pętli), potem jeszcze raz będzie próbował ugryźć 200, 100 itd...
Generalnie jest dobra rada dla początkujących programistów: zanim zaczniesz szukać błędów w systemie i bibliotekach, szukaj u siebie (rzekoma niedokładność decimala)

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