[VBA] wartości zmiennej po zaokrągleniach

0

Witam, mam mały problem z zaokrągleniami, ze zmienną oraz jej wartością w VBA w excelu.

Mam sobie zmienną X as single
Mam sobie kolejną Y as single

W komórce w arkuszu mam zaokrągloną wartość =ZAOKR(SUMA(D6:D10)*8/B27;2) w konkretnym przypadku wartość w niej to 167,33
W pierwszym kroku do zmiennej X przypisuję wartość z powyższej komórki.
Dalej, w pewnym Case do czystej i świeżej zmiennej Y przypisuję zmienną X (która wcześniej nie była w żaden sposób ruszana) Y=X
Po czym zmienna Y jest wpisywana w inną komórkę. I tu się okazuje, że jej wartość to 167,330001831054
Próbowałem w międzyczasie stosować w różne miejsca round, bez większych efektów.
W każdym możliwym kroku, wyświetlenie zmiennej w msgbox pokazuje wartość 167,33 finalnie po wpisaniu jej w komórkę zmienia się w "długiego potwora po przecinku"
Niestety, w tym akurat miejscu potrzebuję wartości dokładnie 167,33

Ma ktoś pomysł jak to osiągnąć?
Dlaczego w ogóle 167,330001831054?
Nic nie rozumiem i głupi jestem :)

1

Znajdź może w wikipedii wprowadzenie do liczb zmiennoprzecinkowych, bez tego leczysz objawy a nie przyczynę

  1. Zasadniczo wszyscy wiedzą (lepiej lub gorzej) że ich dokładność jest ograniczona, że dokładność double jest większa niż single/float itd...
  2. znacznie mniej programistów wie, że jest problem reprezentacji, tj dokładne dziesiętne 167.33 nie istnieje w tym zbiorze, dostaniesz najbliższą binarną powyżej lub poniżej
0

I o takie wyjaśnienie właśnie chodziło - wskazanie w czym się doszkolić i wstępne wyjaśnienie problemu :)
Zapomniałem na początku dodać że jestem sobie zwykłym amatorem i nie zaliczam się nawet do "Zasadniczo wszyscy wiedzą..."
Dzięki wielkie.

0

Tak mnie ten temat gnębił wewnętrznie, od czasu odpowiedzi AnyKtokolwiek.
Z problemem sobie poradziłe ale... pozostała kwestia niewiedzy która mnie gryzie.

W jaki sprytny sposób poradzono sobie z problemem reprezentacji w currency i podobnymi (poza vba), że działają, chociaż fizycznie na poziomie hardware to nadal "010101011100" i ciężko tu zapisać 1/3?

0

@Yanno: składujesz dane jako liczbę "groszy" i następnie tylko wyświetlasz w odpowiedni sposób.

0

To że sobie mogę sobie najpierw pomnożyć, a później podzielić przez 100 i mieć wynik (alternatywnie nazwę to: ustawić przecinek przy wyświetlaniu wyniku w odpowiednim miejscu) to ogarniam. Uczę się działania z komputerem, a nie myślenia :)
Interesuje mnie ta głębsza warstwa działania, ta jaką "widzi" maszyna.

Dla niej liczba to nadal ciąg zer i jedynek. nadal 100 / 3 będzie miało wynik nieprecyzyjny.
Podejrzewam, że samo użycie tego typu zmiennej mówi maszynie jak ma liczyć aby unikać takich wyników.
Jakie to sposoby? Jak to działa? Obcina końcówki liczb i zaokrągla? Może sprawa zaszyta jest w samym formacie zapisu zmiennej?
Tego nie ogarniam. Co gorsza nie wiem nawet czego szukać i google podaje mi dużo śmiecia który do niczego nie prowadzi
A gdy kiedyś będę potrzebował użyć tego "formatu" wolałbym wiedzieć gdzie i jakie pułapki mogą się pojawić.
No i ciekawość, głównie ciekawość mnie motywuje.

0

100/3 również w naszym realnym życiu bez komputerów to problem.

100/3 wspiera się algorytmem (nie ma żadnych operatorów które by załatwiały problem). Może są jakieś naukowe sposoby, ja układam od największego/najmniejszego wyniku (tu są równe - ale mogą to być skutki proporcji i być nierówne) i rozdaję +1gr / -1gr aż do wyzerowania reszty.
Np dobry system magazynowy zarejestruje przyjęcie takiego zakupu jako dwie pozycje 2x33.33 i 1x 33.34

Innym sposobem są działania na ułamkach "prawdziwych"(tj "piętrowych", wspólny mianownik, skracanie, te sprawy), ale chyba nie ma to zastosowania poza pracami studenckimi.

0

No, z moim brakiem doświadczenia, przy początkowym problemie oszacowałem maksymalne zakresy danych wejściowych, sprawdziłem "wielkość" wyniku, dodałem 3 rzędy wielkości na zapas i wyszło, że w każdym możliwych i sensownych wypadków nie zgubię nigdzie grosza. Przynajmniej taką mam nadzieję. Zmiany dzieją się tak daleko po przecinku że realnie nie wpłyną na wynik końcowy wyrażony standardowo zł + gr. W moim przypadku powinno to działać i działa, kosztem ograniczenia wielkości danych wejściowych i ... wydajności (choć przy moim skromnym projekcie to akurat najmniejszy problem).

Teraz sobie kombinuję od paru dni (i po twoim wpisie widzę że kierunek może być ciekawy) jak to wszystko ogarnąć inaczej. Na razie poszedłem w wymyślanie "udawania" ułamków naturalnych i w ogólnym zarysie widzę jak do tego można by dojść. Muszę sobie nad tym posiedzieć jeszcze, chociaż już wiem że i tak będzie to uniknięcie skutków, a nie rozwiązanie.

Projekt vba zakończyłem z sukcesem :) i z rozpędu przesiadłem się na c# wraz z dotsiatką i dodatkami. Trochę mam za dużo excela w pracy aby bawić się w nim jeszcze w domu :)

Ale ... problem jest inter ... językowy jak widzę. Dodatkowo nie umiem odpuścić jak mnie coś zaciekawi i staram się rozgryźć problem do końca. Tutaj ledwo żuję pierwszy kęs i nadal tego nie czuję.
Ale powoli świta mi coś.

A tak przy okazji, mam pytanie z innej beczki.

Kiedyś wyobrażałem sobie, że pisanie takich (jakiś tam) rzeczy to głównie klepanie w edytorze kodu.
Tworząc mój projekt w excelu czasu na klepanie poświęciłem może 10-20% całości. Reszta to rozgryzanie problemu od strony zrozumienia "jak to działa w rzeczywistości", jak ma działać finalnie w produkcie, jak do tego dojść aby było ok. (pomijam testowanie bo to czasowy koszmar)
Zawsze to tak wygląda?
Bo takie przegryzanie się przez nowe problemy to jest to co lubię i chcę.

Dziękuję wszystkim za pomoc.

No nic

0
Yanno napisał(a):

To że sobie mogę sobie najpierw pomnożyć, a później podzielić przez 100 i mieć wynik (alternatywnie nazwę to: ustawić przecinek przy wyświetlaniu wyniku w odpowiednim miejscu) to ogarniam. Uczę się działania z komputerem, a nie myślenia :)
Interesuje mnie ta głębsza warstwa działania, ta jaką "widzi" maszyna.

Koledzy wspomnieli o liczeniu binarnym w groszach. Nie jestem przekonany że każda realna implementacja "decimala" na tym chodziła - na pewno to jest najczęściej wybierana "studencka"
Procesory (np intel) wspierają rozkazy w BCD (binary coded decimal), czyli bajt 0x0807 oznacza dwie "nasze" cyfry 87, plus Carry, pozwala to wydajnie dodawać, odejmować, niewiele trudniej mnożyć, dzielenie bywa kłopotem wydajnościowym.

Miej oczy otwarte, czy typ stałoprzecinkowy, albo dziesiętny na konkretnej platformie ma sztywną długość, czy długość zmienną (np w Javie BigDecimal), czy miejsc dziesiętnych na sztywne 2 albo 4 (muzealny 16bitowy Visual Basic 3.0) , czy zmienną (konieczne aby się dokładnie mnożyło). Zwykle to pozwala zgadnąć jak jest zrobione

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