Zerowanie konkretnych miejsc części dziesiętnej (typ float)

0

Witam,
mam zmienną float x = 12.34542

Przypuśćmy, że chciałbym drugie i trzecie miejsce po przecinku zastąpić zerem. W jaki sposób to najlepiej zrobić?
Jedyne co przychodzi mi do głowy, to zapisać liczbę do łańcucha znakowego i wtedy, ale nie wiem czy to najlepszy sposób.
pozdrawiam

5

Pytanie raczej powinno brzmieć, co tak naprawdę chcesz osiągnąć? Bo Twoje pytanie brzmi jak kiepski pomysł na rozwiązanie jakiegoś problemu. Ani liczby nie są reprezentowane w systemie dziesiętnym przez komputer, ani te reprezentacje nie są dokładne.

0

Odejmij zwyczajnie. Powiedzmy, że chcesz się pozbyć piątki i mieć 12,34042:

12,34542 - 0,005 = 12,34042

Pamiętać należy jednak o tym co powiedział @twonek wyżej.

3

Hint: Jeśli potrzebujesz precyzyjnych floatów dziesiętnych, użyj... floatów dziesiętnych! Wg. tabelki w ZP są to typy: std::* (np. std::decimal32 - GCC to obsługuje). W C są to _Decimal32, _Decimal64 itd. W Visual C++ może być jeszcze inaczej.

Przy czym, floaty dziesiętne są implementowane strikte software'owo, tj. są znacznie wolniejsze niż floaty binarne (ale nie aż tak wolne ;>).

0
barmic napisał(a):

Witam,
mam zmienną float x = 12.34542

Przypuśćmy, że chciałbym drugie i trzecie miejsce po przecinku zastąpić zerem. W jaki sposób to najlepiej zrobić?
Jedyne co przychodzi mi do głowy, to zapisać liczbę do łańcucha znakowego i wtedy, ale nie wiem czy to najlepszy sposób.
pozdrawiam

kiedyś nawet takie coś robiłem - zaokrąglanie od pół włącznie w górę:

double roundf(double w, int n) // n = liczba cyfr po przecinku
{
  double d, f;
  if( n == 2 ) d = 0.01; // zaokrąglanie do grosza
  else for(d = 1; --n >= 0; ) d /= 10;

  if( (f=fmod(w, d)) < 0 ) f += d;
                                     
  return ((f >= d/2) ? w+d : w) - f; // dla f > d/2 będzie to zaokrąglanie do 0.5 górę.
}

1

@pentagol
O, ciekawy pomysł. Let me try.

double myroundfx(double w, int n) {
  double p = pow(10, n);
  return (double)(long long)(w * p + 0.5) / p;
}
0
Gynvael Coldwind napisał(a):

@pentagol
O, ciekawy pomysł. Let me try.

double myroundfx(double w, int n) {
  double p = pow(10, n);
  return (double)(long long)(w * p + 0.5) / p;
}

Może wynik dobry wyjdzie, ale czasowo będzie to chyba znacznie gorsze od mojej wersji,
bo tu używasz pow i dzielenia, co jest chyba dużo bardziej kosztowne od fmod.

0

Mi wychodzi z 3 razy szybciej wersja z fmod.
...sprawdzałem tylko w wersji 32, znaczy zamiast tego: long long, wsadziłem int (jedno tylko :) ).

0

Każdy algorytm który zwraca wartość jako double/float nie jest dokładny.
Jest o tym masa materiału w necie, więc nie będę tego przeklejał.
Rozwiązaniem są typy: wspomniane decimal, integer lub BigNum.

Przykład:
https://gmplib.org/

0

Zrobiłem taki prowizoryczny test (na 32-bitowym kompilatorku - Borlanda):

 
#define N 1000
       uint f[8];
       double *t = new double[N];

        QueryPerformanceFrequency((LARGE_INTEGER*)(f+0));

       for(int k = 0; k < 3; k++)
       {
         for(int i = 0; i < N; i++) t[i] = rndf()*100;

         QueryPerformanceCounter((LARGE_INTEGER*)(f+2));
         for(int i = 0; i < N; i++) roundf(t[0], 2);

         QueryPerformanceCounter((LARGE_INTEGER*)(f+4));
         for(int i = 0; i < N; i++) roundfi(t[0], 2);

         QueryPerformanceCounter((LARGE_INTEGER*)(f+6));
       }

        delete t;

        int t1 = f[4]-f[2];
        int t2 = f[6]-f[4];

        sprintf(s, "%d / %d = %f", t1, t2, (double)t1/t2);

        MessageBox(s, "round", MB_OK);

i dla n=2 wynik był około 0.3, czyli 3.33 razy szybciej z fmod.
dla n = 3, i 4 było okóło 0.5;

a dla n = 0 było to samo, czyli głównie ten pow to spowalnia.

Borland kompiluje floaty na FPU,
a wtedy fmod używa rozkazu fprem, który jest ponoć wolny...
więc na SSE2 powinno być szybciej.

Może jeszcze na MS C++ to sprawdzę..

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