C++ niechciane zaokrąglanie...

2

Wprowadzam liczbę 1234567.89.
Potem mnożę ją przez 100 i po tym pomnożeniu wynik to 123456788.
Próbowałem już z różnymi typami, wychodzi tak samo.
Jakaś drobna podpowiedź ? :-)

long double kwota = 1234567.89;
__int64 kwota_wszystkie_cyfry;
kwota_wszystkie_cyfry = kwota *100 ;

screenshot-20210319194444.png

6

std::round

Przy czym operujesz na floatach, niedokładność obliczeń to coś z czym musisz się liczyć

0

Zrobiłem dziwny myk...

kwota_wszystkie_cyfry = kwota *1000 /10 ;

...i pomogło ;-)

11

Jeżeli kwota to jakieś pieniądze, a wy przechowujecie je i lub obliczanie na double to pamiętajcie, że możecie sobie lub firmie zafundować problemy z urzędem skarbowym, sprawozdaniem finansowym, audytem finansowym, a w średnio optymistycznym przypadku stracicie po prostu dużo czasu na szukaniu zaginionych groszy.

5

Pamiętaj, że współczesne komputery przetwarzają wszystkie liczby (i nie tylko) binarnie - całkowite (int, long), zmiennoprzecinkowe (float, double) itd.

W binarnej reprezentacji float, double czy long double na 99.99% nie da się zapisać dokładnej wartości 1234567.89, a jedynie przybliżenie - gdzie na ostatnim miejscu (to może być choćby i 300-na cyfra znacząca) będzie błąd zaokrąglenia. Bardzo dużo ładnych liczb i ułamków dziesiętnych jest bardzo nieładnych w zapisie binarnym. Triki tu nie pomogą - zawsze wpakujesz się w przypadek, gdy po zrzutowaniu na typ całkowity coś nie będzie się zgadzać, przy dodawaniu wyniki zaczną się lekko rozjeżdżać itd. Może się okazać, że porównanie liczb zmiennoprzecinkowych w rodzaju 1.4 + 2.6 == 4.0 nie będzie prawdziwe, właśnie przez błędy zaokrągleń.

Jak zależy Ci na dokładności, to musisz polegać na dedykowanych typach (albo je sobie stworzyć - w ramach ćwiczenia). Coś jak Decimal czy BigDecimal.

4

Dokładnie da się zapisać tylko liczbę, której mianownik, (postać zwykła ułamka) jest potęgą dwójki.

7

Właśnie odkrywasz przyczynę tego stwierdzenia:
"Ludzie trafiają do więzienia, za operowanie pieniędzmi na liczbach zmiennoprzecinkowych" Robert C. Martin.

2

@Waran3: Warto zauważyć, że na double mamy już niedokładność dla tako "oczywistych" wartości jak 0.1 + 0.2 != 0.3:

#include <iostream>

int main() {
    using namespace std;

    cout.setf(ios::scientific);
    cout.precision(30);

    double x = 0.1, y = 0.2, z = 0.3, s = x+y, r = s-z;

    cout << boolalpha << (s == z) << endl;
    cout << x << endl;
    cout << y << endl;
    cout << z << endl;
    cout << s << endl;
    cout << r << endl;
}

Wynik:

false
1.000000000000000055511151231258e-01
2.000000000000000111022302462516e-01
2.999999999999999888977697537484e-01
3.000000000000000444089209850063e-01
5.551115123125782702118158340454e-17

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