CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

[BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

dział ogólny

[BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez _wędkarz_ » niedziela, 30 grudnia 2012, 12:04

To mój pierwszy post, witam na forum :)

Jestem początkującym jeśli chodzi o programowanie. Mam pewien, tworzę konwerter walut, kursy wprowadzam w float następnie wypisywane są na tablicy, później można sobie konwertować waluty i tu pojawiają się problemy. Po wprowadzeniu kursu w float, wyświetlana liczba w tablicy jest trochę inna co skutkuje też innymi obliczeniami później w konwerterze.
Może zamieszczę screen programiku:
problem.JPG


Próbowałem zastosować taką funkcje, niestety nie chce działać:
Kod: Zaznacz cały
float zaokraglij(float x)
{
int y=x*10000; //przesuwa przecinek o 4 miejsca i pozbywa sie reszty za przecinkie-y jest calkowite
if(y % 10 >=5) y+=10; // jezeli cyfra jednosci >=5
x=(y/10)*0,001; //zmieniamy na zmiennoprzecinkowa
}


potem jest to wywoływane na przykład w taki sposób:
Kod: Zaznacz cały
if (Form1->ComboBox3->ItemIndex==0)
  {
  eur=StrToFloat(Form1->Edit3->Text);
  Form1->Edit3->Text="";
  zaokraglij(eur);
  StringGrid1->Cells[1][1]=eur;
  }

zaokrąglanie oczywiście trzeba też zastosować później przy konwertowaniu

Jakby ktoś pomógł byłoby świetnie.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
_wędkarz_
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): niedziela, 30 grudnia 2012, 10:33
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: CodeBlocks, BCB 6
Gadu Gadu: 0
    Windows 7Firefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Cyfrowy Baron » niedziela, 30 grudnia 2012, 14:52

KOD cpp:     UKRYJ  
  if( Form1->ComboBox3->ItemIndex == 0 )
  {
    eur = StrToFloat(Form1->Edit3->Text);

    Form1->Edit3->Text = "";

    StringGrid1->Cells[1][1] = FloatToStrF(eur, ffGeneral, 7, 4); /* lub FloatToStrF(eur, ffNumber, 7, 4); */
  }


Jak skonwertować tekst na liczbę i odwrotnie.

Dlaczego operacja jest wykonywana tylko wtedy, gdy ComboBox2->ItemIndex jest równy 0, czyli gdy wybrana jest pierwsza pozycja z rozwijanej listy?
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez _wędkarz_ » niedziela, 30 grudnia 2012, 18:15

Chodzi o część "Wprowadzanie Walut", tam gdy wpiszemy wartość i obok wybierzemy w ComboBox3 co to za waluta, wartość przypisuje nam do zmiennej eur, dolar lub np. frank. I ją wtedy zaokrąglamy by pokazać jej wartość w tablicy.
Odnośnie Twojego kodu mam pytanie, po ffGeneral są cyfry, 7 odpowiada za liczbę znaków w liczbie, a 4? myślałem że jest to liczba miejsc po przecinku ale niestety zmieniałem ją i nie miało to żadnego wpływu na wyświetlane liczby :/

Da się jakoś w pamięci zaokrąglić te liczby? Bo tak się teraz zastanawiam potem gdy już mam wprowadzone kursy, przechodzę do konwertowania, kasa jest liczona po kursie z tymi dodatkowymi cyferkami a nie zaokrąglona przez co wychodzi znowu bujny wynik. Np:
prob.JPG


Ok, w trakcie pisania posta sprawdziłem taką oto opcje( w tym przypadku przelicza ze złotówek na euro):
KOD cpp:     UKRYJ  
{
        wartosc=StrToFloat(Form1->Edit1->Text); // Edit1 to jest pole gdzie wpisujemy kwotę do obliczenia
        wyniczek=wartosc/eur;
       Form1->Edit2->Text=FloatToStrF(wyniczek, ffGeneral, 8, 2);
        }
 

W przypadku wyniku np. 8,2 nie dopisuje mi głupich cyferek, niestety nie chce mi do 2 miejsc po przecinku zaokrąglić.
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
_wędkarz_
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): niedziela, 30 grudnia 2012, 10:33
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: CodeBlocks, BCB 6
Gadu Gadu: 0
    Windows 7Firefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Cyfrowy Baron » niedziela, 30 grudnia 2012, 18:52

Jeżeli użyjesz specyfikatora ffGeneral to liczba miejsc po przecinku zawsze będzie wynosić 4. Liczba 7 odnosi się do ilości miejsc całkowitych czyli przed przecinkiem, a więc przy siedmiu będzie to wartość maksymalna 9999999, liczba 4 oznacz liczbę miejsc pop przecinku ale tylko przy specyfikatorze innym niż ffGeneral np. przy ffNumber.

Zapoznaj się z tym postem: http://programowanie.cal.pl/forum/viewtopic.php?f=2&t=1693#p13519

Formatowanie liczby na tekst jest potrzebne dopiero gdy zachodzi potrzeba wyświetlenia wyniku, więc na etapie wykonywania obliczeń zaokrąglanie jest raczej niepożądane.

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
_wędkarz_
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez _wędkarz_ » niedziela, 30 grudnia 2012, 19:28

Nie wiem czemu przy ffGeneral do 4 nie zaokrągla ale z ffNumber ładnie chodzi, więc już nie drążę tematu :)

Dzięki wielkie za pomoc, czas na kolejny wyzwanie-ściąganie kursów ze strony nbp. Czas zacząć przeszukiwać tą stronę i trochę pokombinować samemu, jak będą kłopoty to założę temacik albo się do jakiegoś dołączę.
Avatar użytkownika
_wędkarz_
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): niedziela, 30 grudnia 2012, 10:33
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: CodeBlocks, BCB 6
Gadu Gadu: 0
    Windows 7Firefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Mironas » poniedziałek, 31 grudnia 2012, 12:03

W przypadku liczenia pieniędzy najlepiej stosować typ Currency (w BCB6) zamiast float. Currency zapisuje liczby z 4 miejscami po przecinku i dzięki temu nie musisz martwić się o zaokrąglanie i inne takie. Jest to specjalny typ do obliczeń finansowych.

Za ten post autor Mironas otrzymał podziękowanie od:
_wędkarz_
Avatar użytkownika
Mironas
Programista I
Programista I
 
Posty: 427
Dołączył(a): poniedziałek, 2 stycznia 2012, 19:02
Podziękował : 17
Otrzymał podziękowań: 61
System operacyjny: Windows 10
Kompilator: C++Builder 10.3 Rio
TMS Components Pack
Gadu Gadu: 0
    Windows XPChrome

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Cyfrowy Baron » poniedziałek, 31 grudnia 2012, 12:51

Użycie specyfikatora ffCurrency ma tą wadę, że do wyniku konwersji zostanie dodany symbol waluty zdefiniowany w aplecie Panelu Sterowania Opcje regionalne i językowe. Więc w tym przypadku - gdy mamy do czynienia z różnymi walutami to raczej nie wchodzi w grę.

Masz jednak rację co do funkcji CurrToStr, która zawsze zwróci tylko 4 znaki po przecinku bez żadnych dodatkowych symboli:

KOD cpp:     UKRYJ  
float x = 123.4567891;
 Edit1->Text = CurrToStr(x); // wynik: 123.4568


Jak widać wynik został zaokrąglony w górę, gdyż po liczbe 4567 występuje cyfra 8. Gdyby tam była cyfra mniejsza od 5 (np. 123.4567491) to wynik zostałby zaokrąglony w dół.
Przydać może się jeszcze funkcja CurrToStrF, która działa podobnie, pozwala jednak określić ile liczb zostanie podanych po przecinku, ale znaczące będą jednak tylko cztery cyfry, powyżej zostaną dodane same 0:

KOD cpp:     UKRYJ  
 float x = 123.4563491678901234;
 Edit1->Text = CurrToStrF(x, ffNumber, 10); // wynik: 123,4564000000




Pozostaje problem zapisu liczb dziesiętnych. Jeżeli w systemie jako separator został zdefiniowany przecinek, a użytkownik użyje kropki to konwersja tekstu na liczbę się nie uda - wyskoczy błąd.
Opis sytuacji: Użytkownik w polu Edit2 wpisał liczbę dziesiętną z separatorem w postaci kropki, próba konwersji tekstu na liczbę się nie powiedzie:

KOD cpp:     UKRYJ  
float x = StrToFloat( Edit2->Text );


W takiej sytuacji trzeba sprawdzić jakiego separatora użył użytkownik i ustawić właściwy.

KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TFormatSettings fSet;
 GetLocaleFormatSettings(1045, fSet);

 wchar_t sDec = fSet.DecimalSeparator;

 int dPos = Edit2->Text.Pos( "." );

 if( dPos > 0 )    /* zmieniamy separator na użyty przez użytkownika */
 {
  fSet.DecimalSeparator = '.';
 }
 else
 {
  fSet.DecimalSeparator = ',';
 }

 float x = StrToFloat(Edit2->Text, fSet);


 fSet.DecimalSeparator = sDec; /* przywracamy systemowy separator */
 Edit1->Text = CurrToStr(x, fSet);
}


Ten kod dokona konwersji na liczbę niezależnie od tego jakiego separatora użyje użytkownik (w grę wchodzą tylko kropka i przecinek), a wynik zostanie wyświetlony z separatorem właściwym dla ustawień systemowych.
Kod nie zadziała chyba w środowisku C++Builder 6 i starszych.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Mironas » poniedziałek, 31 grudnia 2012, 13:22

Cyfrowy Baron napisał(a):Użycie specyfikatora ffCurrency [...]


Miałem na myśli typ zmiennych Currency (zamiast float) a nie specyfikator ffCurrency. Dzięki temu nie ma potrzeby martwić się zaokrąglaniem:
KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  Currency eur = StrToCurrDef(Edit1->Text, 0.0);
  Currency kurs = StrToCurrDef(Edit2->Text, 0.0);
  Currency pln = eur * kurs;

  Label1->Caption = eur;
  Label2->Caption = kurs;
  Label3->Caption = pln;
}
 

Oczywiście dobrze było by jeszcze zabezpieczyć się przed wpisywaniem przecinaka/kropki lub innych niepoprawnych znaków w Edit.
Avatar użytkownika
Mironas
Programista I
Programista I
 
Posty: 427
Dołączył(a): poniedziałek, 2 stycznia 2012, 19:02
Podziękował : 17
Otrzymał podziękowań: 61
System operacyjny: Windows 10
Kompilator: C++Builder 10.3 Rio
TMS Components Pack
Gadu Gadu: 0
    Windows XPChrome

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Darek_C++ » poniedziałek, 31 grudnia 2012, 14:29

Mironas napisał(a):W przypadku liczenia pieniędzy najlepiej stosować typ Currency (w BCB6) zamiast float. Jest to specjalny typ do obliczeń finansowych.
Testowałeś przy obliczeniach VAT dla większej liczby pozycji ? Pytam z ciekawości, bo chodzi o to czy będą prawidłowe zaokrąglenia :)
Avatar użytkownika
Darek_C++
Elektrowied
Elektrowied
 
Posty: 454
Dołączył(a): piątek, 25 lipca 2008, 14:33
Podziękował : 66
Otrzymał podziękowań: 4
System operacyjny: Windows XP Pro SP2
Kompilator: Turbo Explorer C++
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Mironas » poniedziałek, 31 grudnia 2012, 14:48

Typ Currency to specjalny typ do obliczeń finansowych, więc chyba poprawnie będzie działał.
Używałem go w programie z funkcjami księgowymi, i nigdy księgowa nie zgłaszała zastrzeżeń. Ale przyznaję, że osobiście jakichś specjalnych, dokładnych testów nie robiłem. Po prostu zaufałem, że jest to właściwy typ - i nie miałem z nim problemów.

[Edit]
Use Currency to hold monetary values
Avatar użytkownika
Mironas
Programista I
Programista I
 
Posty: 427
Dołączył(a): poniedziałek, 2 stycznia 2012, 19:02
Podziękował : 17
Otrzymał podziękowań: 61
System operacyjny: Windows 10
Kompilator: C++Builder 10.3 Rio
TMS Components Pack
Gadu Gadu: 0
    Windows XPChrome

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Cyfrowy Baron » poniedziałek, 31 grudnia 2012, 15:15

Użycie typu Currency zamiast np. float ma tylko tą zaletę, że możesz pod ten typ podstawiać zarówno liczby jak i tekst. W sytuacji gdy funkcja FloatToStr oczekuje jako argumentu wartości typu double i nie akceptuje typu np, String, to funkcja CurrToStr zaakceptuje zarówno typ double, int, String itp. By używać funkcji CurrToStr jak i StrToCurr nie musisz się posługiwać typem Currency. Jeżeli jednak już zdecydujesz się na ten typ to możesz bez problemu wykonywać obliczenia na zmiennych Currency z których jedna pobiera np. liczbę z Edit a druga z typu float.

KOD cpp:     UKRYJ  
 Currency x = Edit2->Text;
 Currency y = 23.567;
 Currency wynik = x * y;
 Edit1->Text = wynik;


oczywiście to samo można osiągnąć stosując typ float:

KOD cpp:     UKRYJ  
float x = Edit2->Text.ToDouble() ;
 float y = 23.567;
 float wynik = x * y;
 Edit1->Text = wynik;


Stosując Currency uzyskujemy jednak zaokrąglenie, ale tak też to uzyskamy:

KOD cpp:     UKRYJ  
Currency x = Edit2->Text;
 float y = 23.567;
 Currency wynik = x * y;
 Edit1->Text = wynik;


Stosując Currency nie musimy się jednak martwić co przypisujemy zmiennej.

Stosując Currency narażamy się jednak na zbyt duże zaokrąglenie jeszcze przed wykonaniem obliczeń, np:

KOD cpp:     UKRYJ  
 Currency x = 12.3456789;              
 Currency y = 23.23456789;            
 Currency wynik = x * y;
 Edit1->Text = wynik;


Wynik: 286,8474 - podczas gdy prawidłowy wynik z zaokrągleniem do 4 miejsc po przecinku powinien wynieść 286,8465 - różnica 0.0009 - dlaczego: Dlatego że wartość 12.3456789 została zaokrąglona do 12.3457 a wartość 23.2346
Skoro wynik ma być z dokładnością do 4 miejsc po przecinku, to co lepiej użyć typu Currency czy double (float)? Tak się jednak stanie tylko wtedy gdy będziemy podstawiać wartości z liczbą miejsc po przecinku większą niż 4.



Zwracam jednocześnie uwagę na konieczność stosowania właściwego separatora. Nie w każdym systemie musi to być przecinek. Jeżeli separator nie zostanie oprogramowany i tworząc program założyć, że użytkownik ma ustawiony przecinek, a faktycznie będzie miał kropkę, to program w pewnych sytuacjach nie będzie działał.

Za ten post autor Cyfrowy Baron otrzymał podziękowanie od:
Darek_C++
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Mironas » poniedziałek, 31 grudnia 2012, 15:46

Do precyzyjnych obliczeń matematycznych powinno się stosować float/double i co najwyżej zaokrąglać wyświetlane wyniki.

Do obliczeń FINANSOWYCH powinno się stosować Currency, bo tutaj nie operuje się na liczbach z dokładnością większą niż 4 miejsca po przecinku. Taki jest (wg mojej skromnej wiedzy) standard stosowany w księgowości, bankowości, itp. Jeśli zastosujesz dokładniejsze obliczenia to wyniki nie będą zgodne z innymi tego typu programami. Jednak zaznaczam - nie jestem ekspertem w księgowości - może mi się tylko tak wydaje.
Avatar użytkownika
Mironas
Programista I
Programista I
 
Posty: 427
Dołączył(a): poniedziałek, 2 stycznia 2012, 19:02
Podziękował : 17
Otrzymał podziękowań: 61
System operacyjny: Windows 10
Kompilator: C++Builder 10.3 Rio
TMS Components Pack
Gadu Gadu: 0
    Windows XPChrome

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez Cyfrowy Baron » poniedziałek, 31 grudnia 2012, 16:24

Też tego nie wiem, dlatego zwróciłem uwagę na fakt, że Currency zaokrągla wartości zawsze do 4 cyfr po przecinku niezależnie od tego ile się ich poda.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez polymorphism » poniedziałek, 31 grudnia 2012, 19:01

Do obliczeń FINANSOWYCH powinno się stosować Currency, bo tutaj nie operuje się na liczbach z dokładnością większą niż 4 miejsca po przecinku.

Tutaj przede wszystkim chodzi o to, że typ zmiennoprzecinkowy wprowadza pewne błędy, które mogą się sumować, a to w finansach niedopuszczalne. Currency przechowuje wartość w postaci całkowitoliczbowej (w jednostkach 0,0001), dzięki czemu wspomniane problemy znikają. Liczba miejsc po przecinku może i mała, ale w finansach nie jest ona aż tak istotna - w większości walut wystarczą 2 miejsca (grosz -> 0,01), czyli są jeszcze dwa miejsca zapasu.
C++ Reference - opis wszystkich klas STL-a i funkcji C.

Za ten post autor polymorphism otrzymał podziękowanie od:
Darek_C++
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: [BCB 6] Zaokrąglanie float do 4 miejsc po przecinku

Nowy postprzez _wędkarz_ » wtorek, 1 stycznia 2013, 13:49

Wow, nieźle się rozpisaliście :)
Pozmieniam z float na Currency, zobaczę jak działa i postaram się zrobić to zabezpieczenie co do separatora. Natomiast teraz mam większy problem, XP na VirtualBoxie mi się coś posypał i nie mam dostępu do danych :/
Avatar użytkownika
_wędkarz_
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): niedziela, 30 grudnia 2012, 10:33
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: brak systemu
Kompilator: CodeBlocks, BCB 6
Gadu Gadu: 0
    Windows 7Firefox

Następna strona

  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 8 gości