[avr-gcc] zaokraglanie :))

Feb 15, 2005 26 Replies

Witam, mam liczbe zmienno przecinkowa i chcialbym ja zamienic na liczbe calkowita, jednak z zachowaniem zasad zaokraglania. Jaka funkcja to czyni?


(int) (a + 0.5), na przykład

Waldek

#include <stdio.h>

int main( void ) { double a=0.9999, b=1.0000; printf( "%.4lf + %.4lf = %d\n", a, b, (int) (a+b) ); return 0; }

Co otrzymamy w wyniku? Oczywiście, że jeden! Z liczbami zmienno przecinkowymi jest trochę klopotu, i trzeba być bardzo ostrożnym. Jak pamietam (x86-visual-c++-6.0) to taka funkcję (dobrą) sam musiałem sobie napisać. A zasady zaokrąglania można nietrudno zaimplementować.

No, no, trochę przesadziłem... to nie jest takie łatwe, w zależności jakie sobie przyjmiesz założenia, do którego miejsca zaokrąglanie, ile miejsc po przecinku brać pod uwagę. Zrobienie uniwersalnej funkcji nie jest łatwe. Jeśli masz mało miejsca w swoim avr-ku to zastanowiłbym się nad implementacją stałego przecinka.

Tue, 15 Feb 2005 22:17:57 +0100, na pl.misc.elektronika, Łukasz Góralczyk napisał(a):

Prawda, zwłaszcza że są jeszcze jakieś specjalne szczególiki wymagane w księgowości. Ale tu miało byc zwyczajne zaokrąglenie do całkowitych, IMHO ze zwyczajowym : część ułamkowa <0.5 - do dołu , >=0.5 - do góry. Wtedy wystarczy np.

int Round(double value) { double tolow=floor(value); if((value-tolow) < 0.5) return (int)tolow; else return (int)tolow+1 ; }

A i tak dużo zasobów pochłania.

Hmmm.... Nie prościej: int(value + 0.5)?

Oczywiście implementacja i sposób użycia argumentów zależny od jężyka programowania ale dotąd uzywałem zawsze (już kilkanaście lat) tego sposobu i jest niezawodny.

Użytkownik Łukasz Góralczyk napisał:

No oczywiście.. 1+0.999 = 1.9999, ale że konwersja (int) ucina po prostu końcówkę to dostajemy 1. Gdyby zrobić tak jak podane wyżej: (int) (a+b+0.5) byłby chyba dobry wynik ?!?

Użytkownik RoMan Mandziejewicz napisał:

<ciach>

A do zaokrąglania do dowolnego miejsca po przecinku taka konwersja też sie sprawdza (oczywiście pochłania trochę liczenia ;/

float a = 1.738287; float wynik; int miejsce = 2;

wynik = ( ( (int) (a*pow(10,miejsce) + 0.5) )/pow(10,miejsce));

-> wynik == 1.7400

Nie miałem z tym raczej problemów, więc po co sobie komplikować życie ;-)

[...]

[...]

Mało tego - mozna jej uzyć do zaokrąglania niekoniecznie do liczby miejsc po przecinku... Implementacja moja - ciekaw jestem, kto rozpozna język ;-) Funkcja zawiera błąd przy zaokragleniu w górę - działanie swiadome, wynikające z wiedzy, że zaokrąglana liczba nie ma aż tylu miejsc po przecinku. Napisana 11.07.1993 roku ;-)

Parametry: KWOTA - liczba do zaokrąglenia DO - z jaką dokładnością zaokrąglamy (2 miejsca po przecinku to

0.01, z dokładnością do tysięcy: 1000) - bardzo ciekawe efekty występują przy stosowaniu ciekawych liczb ;->

===8<=== PARAMETERS KWOTA, DO, METODA

DO CASE CASE M.METODA = 1 && ZAOKRĄGENIE KSIĘGOWE M.METODA = 0.5 CASE M.METODA = 2 && ZAOKRĄGLENIE W GÓRĘ M.METODA = 0.999999 CASE M.METODA = 3 && ZAOKRĄGLENIE W DÓŁ M.METODA = 0 ENDCASE

RETURN SIGN(M.KWOTA) * M.DO * INT(ABS(M.KWOTA/M.DO)+M.METODA) ===8<===

On Tue, 15 Feb 2005 22:44:47 +0100, Jurek Szczesiul snipped-for-privacy@wycin.ep.com.pl> wrote: [.....]

A próbowaleś przynajmniej sprawdzić jak rozwiązanie Waldka zadziała np. dla 1.49, 1.50 i 1.51? :-) A jest mniej kosztowne - tylko jedno dodawanie zmiennoprzecinkowe. Problem jest taki, że dla liczb ujemnych będzie działać niekoniecznie tak, jakbyśmy tego oczekiwali. :-) Twoje zdaje się również będzie działać w podobny sposób. :-)

Regards, /J.D.

On Tue, 15 Feb 2005 22:49:49 +0100, RoMan Mandziejewicz snipped-for-privacy@pik-net.pl wrote: [.....]

Dla liczb ujemnych równiez jest niezawodny? :-)

Regards, /J.D.

Trochę dalej podałem konkretną funkcję... Sprawdź.

Tue, 15 Feb 2005 22:49:49 +0100, na pl.misc.elektronika, RoMan Mandziejewicz napisał(a):

Pewnie , że prościej. Nie ma to jak sobie pokomplikować życie ;-[

15 Feb 2005 23:38:06 +0100, na pl.misc.elektronika, Jan Dubiec napisał(a):

Jasne, że spróbowałem - tylko oko krzywo spojrzało na wynik ;-[

- i nastąpiła wędrówka obwodnicą ;-)

Podana funkcja implementuje coś innego niż int(value + 0.5).

Regards, /J.D.

Piotr Buczynski wrote: [ciach]

Umnkęło mi, że kolega postujący chciał zaokrąglenia do liczby całkowitej

- to upraszcza problem (jeden z kolegów podał już poprawne rozwiązanie).

A co do 0.5:

#include <stdio.h>

int main( void ) { double a=0.1, b=1.0; printf( "%.4lf + %.4lf = %d\n", a, b, (int) (a+b+0.5) ); return 0; }

Powinno być 2, a jest nadal 1 :) . Pozdrawiam serdecznie.

Chyba się nie wyspałeś. Zaokrąglenie 1.1 ma dać 2?

powinno być 1 i nadal jest 1. 1.0 + 0.1 = 1.1, zaokrąglone wychodzi 1.

Waldek

Ej spiochy - a 0.5 widzicie ?

To co przepraszam robi avr-gcc z -1.6 przy konwersji ?

J.

0.5 jest 'poprawką' służacą do poprawnego zaokrąglania. I jest rzeczą oczywistą, że in(1.6) daje w wyniku 1. [...]

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required