Nowe posty

Autor Wątek: jak w C++ robić operacje na pieniądzach  (Przeczytany 2826 razy)

Offline MateuszA

  • Users
  • Użytkownik
  • **
  • Wiadomości: 70
    • Zobacz profil
jak w C++ robić operacje na pieniądzach
« dnia: 2016-10-12, 22:36:09 »
Paweł mam pytanie kiedyś mi napisałeś że jest specjalne miejsce dla ludzi którzy do obliczeń finansowych używają float double i temu podobnych. A teraz chciałbym się zabrać za tą część programu możesz mi coś poradzić?

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2534
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
    • keybase.io/pkraszewski
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #1 dnia: 2016-10-13, 06:16:11 »
Najprościej trzymać kwotę wyrażoną w groszach (albo dziesiątych/setnych grosza, jak trzeba większej kontroli nad zaokrąglaniem) na dużym int, np int64_t. Jest to metoda nazywana "decimal fixed point" albo w skrócie typ decimal.

Dobrym ćwiczeniem byłoby zawinięcie tego w klasę z implementacja operatorów arytmetycznych i wyjścia-wejścia.
Paweł Kraszewski
~Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline MateuszA

  • Users
  • Użytkownik
  • **
  • Wiadomości: 70
    • Zobacz profil
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #2 dnia: 2016-10-13, 21:13:58 »
Czyli chodzi o to ze zł to int i grosze to int a później to się łączy? Czy dobrze rozumiem.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2534
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
    • keybase.io/pkraszewski
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #3 dnia: 2016-10-13, 21:24:01 »
Nie. W ogóle nie posługujesz się złotówkami. 15.50 zł to 1550 groszy i trzymasz to jako 1550 w int. Wszystkie operacje typu dodawanie i odejmowanie wartości oraz mnożenie i dzielenie wartości przez skalar (żeby nie mieć groszy kwadratowych) działają poprawnie, tylko trzeba pamiętać, że wynik to x/100 złotych i x%100 groszy.
« Ostatnia zmiana: 2016-10-13, 21:26:12 wysłana przez Paweł Kraszewski »
Paweł Kraszewski
~Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline MateuszA

  • Users
  • Użytkownik
  • **
  • Wiadomości: 70
    • Zobacz profil
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #4 dnia: 2016-10-13, 21:38:04 »
A mam takie pytanie bo mam coś takiego do napisania jak smart saver. Jest to opcja w banku która zaokrągla wydane pieniądze do pełnej liczby i resztę przelewa na konto oszczędnościowe. chodzi o to gdy place kartą np. 33,33 to bank bierze to jako 35 zl i od tego odejmuje 33,33 i 1,67 przelewa na konto lub jak place 16 zl to na konto oszczędnościowe przelewają mi 4zł. I to chciałem zrobić ze mam grosze osobno i odejmuj je od 100 i reszta to grosze na konto i dodaje jeden do części zł a później zł dodaje tak długo aż będzie podzielne przez 5.

Offline Paweł Kraszewski

  • Administrator
  • Guru
  • *****
  • Wiadomości: 2534
  • Lenistwo jest matką potrzeby = babcią wynalazku
    • Zobacz profil
    • keybase.io/pkraszewski
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #5 dnia: 2016-10-14, 09:16:44 »
money.h
#ifndef MONEY_H
#define MONEY_H

#include <inttypes.h>
#include <iomanip>
#include <iostream>

template <typename T>
class Money {
 private:
  T amount;

 public:

  // Konstruktory
  Money() : amount( 0 ) {}
  Money( const Money<T>& m ) : amount( m.amount ) {}

  // Explicit daje to, że nie robią się automatyczne konwersje typów
  explicit Money( T am ) : amount( am ) {}
  explicit Money( double d ) : amount( d * 100 ) {}

  // Operator przypisanie

  Money<T>& operator=( const Money<T>& m ) { amount = m.amount; }
  Money<T>& operator=( T am ) { amount = am; }

  // Dodawać i odejmować mozemy tylko 2 obiekty Money

  inline friend Money<T> operator+( const Money<T>& m1, const Money<T>& m2 ) {
    return Money<T>( m1.amount + m2.amount );
  }
  inline friend Money<T> operator-( const Money<T>& m1, const Money<T>& m2 ) {
    return Money<T>( m1.amount - m2.amount );
  }

  // W mnożeniu i dzieleniu drugi argument NIE JEST typu Money.
  // Dzięki temu Money64(5.0)*5 działa jak oczekiwano, dając 25zł

  inline friend Money<T> operator*( const Money<T>& m1, double v ) {
    return Money<T>( T( m1.amount * v ) );
  }

  inline friend Money<T> operator/( const Money<T>& m1, double v ) {
    return Money<T>( T( m1.amount / v ) );
  }

  // Argumenty w odwrotnej kolejności, dzielenie nie ma sensu.

  inline friend Money<T> operator*( double v, const Money<T>& m1 ) {
    return Money<T>( T( m1.amount * v ) );
  }

  // Wyświetlenie sformatowanej wartości

  inline friend std::ostream& operator<<( std::ostream& o, const Money<T>& m ) {
    return ( o << ( m.amount / 100 ) << '.' << std::setfill( '0' )
               << std::setw( 2 ) << ( m.amount % 100 ) )<<" PLN";
  }

  // Zaokrąglenie w górę

  inline Money<T> RoundUp( Money<T> to ) const {
    T r = to.amount * T( ( amount + to.amount - 1 ) / to.amount );
    return Money<T>( r );
  }

  // Explicit wyłącza automatyczne rzutowanie.
  // Nie działa
  //  Money64 M(5.0);
  //  double d = M;
  // Trzeba zrobić
  //  double d = static_cast<double>(M);
  //
  // Upierdliwe, ale pozwala uniknąć błędów gdy coś się automatycznie ale
  // nieplanowo zrzutuje w tle.
  explicit operator double() const { return double( amount ) / 100.0; }
  explicit operator T() const { return amount / 100; }
};

// Rozmiar 64bity
typedef Money<int64_t> Money64;

// Rozmiar 32bity
typedef Money<int32_t> Money32;

#endif  // MONEY_H

main.cpp
#include "money.h"
#include <iostream>

using std::cout;
using std::endl;

int main( int argc, char *argv[] ) {
  Money64 m1( 3.50 );
  Money64 m2( 13.0 );
  Money64 m3 = m1 + m2;

  cout << "M1=" << m1 << endl;
  cout << "M2=" << m2 << endl;
  cout << "M1+M2=" << m3 << endl;

  cout << m3 << " zaokrąglone w górę do 1zł=" << m3.RoundUp( Money64( 1.0 ) )
       << " reszta " << m3.RoundUp( Money64( 1.0 ) ) - m3 << endl;
  cout << m3 << " zaokrąglone w górę do 5zł=" << m3.RoundUp( Money64( 5.0 ) )
       << " reszta " << m3.RoundUp( Money64( 5.0 ) ) - m3 << endl;
  cout << m3 << "  zaokrąglone w górę do 50zł=" << m3.RoundUp( Money64( 50.0 ) )
       << " reszta " << m3.RoundUp( Money64( 50.0 ) ) - m3 << endl;

  cout << m3 << " * 3 = " << m3 * 3 << endl;
  cout << "3 * " << m3 << " = " << 3 * m3 << endl;

  cout << m3 << " / 3 = " << m3 / 3 << endl;

  return 0;
}

Wynik
M1=3.50 PLN
M2=13.00 PLN
M1+M2=16.50 PLN
16.50 PLN zaokrąglone w górę do 1zł=17.00 PLN reszta 0.50 PLN
16.50 PLN zaokrąglone w górę do 5zł=20.00 PLN reszta 3.50 PLN
16.50 PLN  zaokrąglone w górę do 50zł=50.00 PLN reszta 33.50 PLN
16.50 PLN * 3 = 49.50 PLN
3 * 16.50 PLN = 49.50 PLN
16.50 PLN / 3 = 5.50 PLN
Paweł Kraszewski
~Gentoo/FreeBSD/OpenBSD/Specjalizowane customy

Offline MateuszA

  • Users
  • Użytkownik
  • **
  • Wiadomości: 70
    • Zobacz profil
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #6 dnia: 2016-11-16, 16:40:00 »
Powiem tak nie bardzo to rozumiem :D

Offline Mateusz Leśmian

  • Users
  • Nowy na forum
  • *
  • Wiadomości: 3
    • Zobacz profil
Odp: jak w C++ robić operacje na pieniądzach
« Odpowiedź #7 dnia: 2019-11-13, 14:00:35 »
też się chyba jeszcze muszę podszkolić