Wyświetlanie w PHP dwóch zer po przecinku
Mała ciekawostka (może znana i suchar), wyświetlić po przecinku dwa zera. Pewien koleś uczepił się mnie o to i koniecznie chciał, żeby cena była wyświetlana z dwoma cyframi po przecinku (nawet jeśli to były zera). Okazało się, że to jest dość dziwny problem.
Załóżmy, że mamy cyfrę 1.00. Po jej wyświetleniu zobaczymy jedynie "1". Rzutowanie tej wartości do string [ (string)(1.00) ], skutkuje tym samym. Ponieważ nie chciało mi się myśleć, ani szukać zrobiłem troszkę naokoło. Do tej cyfry dodałem 0.001, a później przy użyciu funkcji substr wyciąłem tą ostatnią cyfrę i nagle PHP wyświetla dwa zera po przecinku! Całość wygląda, mniej więcej, tak:
<?php
$a = 1.00;
$a += 0.001;
$a = substr($a, 0, -1);
echo $a;
// Propozycja Jan'a IMHO lepsza ;p
echo sprintf("%.2f", $a);
?>
Czasami ten język faktycznie bywa dziwny, albo to ja coraz bardziej dziwaczeję... o0
Komentarze
Disclaimer
Jakkolwiek jestem właścicielem tego bloga, nie ponoszę odpowiedzialności za kometarze napisane przez innych obywateli tego wolnego kraju.
Zastrzegam sobie prawo do kasowania/modyfikowania komentarzy (jeśli uznam to za stosowne).
Dodaj komentarz
Tylko zalogowani użytkownicy mogą komentować.
#1
A settype(‘float’, $zmienna)?
Albi | #
#2
sprintf(”%.2f”, $a) jest lepszym rozwiązaniem… Znacznie lepszym
jan | #
#3
Popieram, zapomniałem o tym ^^
Albi | #
#4
Albi: nie
Jan: na serwerze, na który to wgrałem, sprintf nic nie pokazał
radmen | #
#5
Jan: omfg, mój bład…
radmen | #
#6
number_format?
BTM | #
#7
number_format jest dla lamerów, nie ? ;-)
Ptfr | #
#8
Ha, sekunda :P
BTM | #
#9
He, niech ta notka w takim razie zostanie jako taka sobie ciekawostka.. ;p
radmen | #
#10
Jakbym się nie nauczył C to też bym pewnie nie wiedział :)
wzs | #
#11
Cholera mnie przez myśl nie przeszła funkcja „sprintf”, choć kiedyś tam się z nią spotkałem… ;p
radmen | #
#12
Proponuję eksperyment! Zmienić wartość zmiennej a na 1.0001! Zobaczymy, czy wówczas wyświetlone zostaną dwa miejsca po przecinku.
Poza tym 1.00 to nie cyfra!
mina86 | #
#13
a moim zdaniem do zapisu kwot równie świetnie nadaje się:
number_format($liczba, 2, ‘,’, ‘ ‘);
:)
i ani trochę to lamerskie, za to kwota wyświetlana będzie prawidłowo…
mls | #
#14
Albi, a na przyszłość zamiast settype wygodniej i krócej jest stosować zapis:
(float)$zmienna :)
mls | #
#15
Mina: gdy dasz 1.001 to cyfra bedzie pokazana prawidłowo. Poza tym w większości programów liczby rzeczywiste zamiast przecinka (stosowanego u nas) mają kropki, także 1.00 jest cyfrą
mls: może i tak, choć nie chce mi się babrać. Sposób Jan’a jest w tym momencie najciekawszy
radmen | #
#16
Mina: nie, 1.00 to liczba, składająca się z cyfr 1 i 0 ;-)
BTM | #
#17
W notacji angielskiej części dziesiętne oddzielane są poprzez kropkę a w notacji polskiej poprzez przecinek. Jeśli wywoła się number format bez dodatkowych atrybutów to znakiem oddzielającym całości od dziesiętnych będzie właśnie kropka :) Także tak czy siak 1.0 to liczba ;)
krysk | #
#18
Wiem, że jak dam 1.001 to będzie dobrze. Mówię o przypadku, gdy zmeinna a będzie miała wartość 1.0001. Podając ten przykład pokazuję, iż Twoje rozwiązanie nie dość, że nie jest najoptymalniejsze, to nie jest też poprawne w ogólnym przypadku.
I nie, „1.00” to z pewnością nie cyfra, nieważne czy uznamy to za liczbę czy nie, to na pewno nie jest to cyfra.
mina86 | #
#19
Wszystkie te sposoby o kant dupy potłuc. Już wiem jak powstają takie potworki programistyczne pisane przez sprintf’owych haxorów.
Polecam zapoznać się z lokalizowaniem liczb:
http://framework.zend.com/manual/en/zend.locale.parsing.html
DrLex | #
#20
Teraz konkurs bez nagród: Co programiście daje lokalizacja liczb ponad to co umożliwia number_format()?
mina86 | #
#21
@mina86 jak piszesz aplikację dla swojej babci to możesz sobie używać co Ci popadnie. Jak tworzysz aplikację wielojęzyczną np. CMS, ERP lub dowolną rzecz, która będzie miała swój globalny użytek, to raczej lokalizowanie i normalizacja liczb jest niezbędna (już nawet nie będę wspominał o formatowaniu walutowym itd.).
Właśnie przez takie myślenie jak Twoje UTF8 pojawiło tak późno i przez wiele lat przez taki brak wyobraźni ludzie rwali sobie włosy z powodu systemów kodowania itd. itp. przykładów można mnożyć...
DrLex | #
#22
„Jak tworzysz aplikację wielojęzyczną [...], która będzie miała swój globalny użytek” to tak, a jeśli nie? Czy naprawdę muszę od razu się bawić w jakieś Zendy, gdy piszę aplikacje dla swojej babci (obecnie nie mam żadnych żywych babć, ale to już szczegół)? Nie lubię stosować armat do zabijania komara, „bo tak.”
mina86 | #
#23
@mina86 i dlatego żadnej armaty nie stworzysz. Będziesz zasilał gąszcz pseudo programistów piszących kod jak hindusi. Potem dopiero okazuje się, że trzeba cały projekt refaktoryzować bo ktoś zamiast dobrej roboty packę na komary zrobił.
Im wcześniej nabierzesz dobrych nawyków tym mniej potem będziesz cierpiał zawodowo.
DrLex | #
#24
Jeżeli celem moim będzie zniszczenie czołgu, skorzystam z armaty. Jeżeli celem moim jest zabicie komara, skorzystam z ręki. Tak to jakoś zazwyczaj robię, że staram się dobierać narzędzia do potrzeb, a nie stosować wszędzie to samo, niezależnie czy jest sens.
mina86 | #
#25
DrLex – IMO przesadzasz. W zadanym temacie nie było napisane „jak wyświetlić liczbę do 2 cyfr po seperatorze, zakładając, że serwer znajduje się w rękach ortodoksyjnych żydów, a odbiorcą ma być piesek brytyjskiej królowej” – są momenty kiedy używasz prostych metod, a są też takie, kiedy używasz zaawansowanych klas. Efektem Twojego rozumowania jest Java albo C#, gdzie „Hello world” zawiera 5 „public partial class” etc.
Zresztą, robiąc stronę w tysiącach języków wciąż używałbym number_format() lub sprintf() przechowując odpowiednie formatowanie w odpowiedniej zmiennej/stałej przekazywanej jako parametr.
BTM | #
#26
@mina86 aspirujesz do bycia mistrzem dyskursu! Pozwól, że wytłumaczę Ci to w ten sposób. W tym konkretnym przypadku koleś doczepił się o te głupie miejsca po przecinku, więc zabito problem haxorską funkcją sprintf.
A teraz pójdźmy dalej. Idąc dalej Twoim ichtiologicznym sposobem myślenia, załóżmy, że ten sam koleś by się uczepił, że chce mieć wyświetlane liczby zgodnie ze standardami obowiązującymi w różnych krajach w zależności od wybranego kraju i wtedy ty jako haxor vel „hakeruje sprintf” zacząłbyś pisać setki ifów elsów, switche i inne bagno, żeby wszystkie te przypadki rozważyć, bo nie miałbyś w nawyku stosowania gotowych komponentów.
Jednym słowem stworzyłbyś czołg zbudowany z łapek na komary.
DrLex | #
#27
BTM trochę się mylisz niestety, widać nie miałeś z tym problemem w życiu do czynienia…
DrLex | #
#28
No jakoś nie widzę problemu. Chyba, że mówimy wyłącznie o kwotach, lub innych wartościach nie posiadających konkretnego odwzorowania w różnych „localach” – wtedy, tak, można stworzyć sobie klasy czy co tam jeszcze chcesz. W wypadku podania „liczby” (nie sprecyzowano co odwzorowuje) nie ma takiej IMO potrzeby.
BTM | #
#29
Wszystko fajnie, każdy ma trochę racji… nie rozumiem tylko, co ma do tego ichtiologia ;) Wszak dzieci i ryby programów nie piszą ;)
Ptfr | #
#30
Skąd wnioskujesz, iż zacząłbym pisać setki ifów? Gdybym miał pisać stronę wielojęzyczną (albo nawet jednojęzyczną, ale taką, że język można sobie ustawić w panelu administracyjnym) zastosowałbym (lub napisał samemu, gdybym potrzebengo komponentu nie znalazł) jakiś komponent, który robiłby to co bym potrzebował.
mina86 | #
#31
Doskonałym przykładem jest kod źródłowy osCommerce właśnie pisany w sposób, byleby działało. W efekcie projekt ten osiągnął totalne stadium chaosu i żaden developer nie chce się babrać w tym bagnie.
Wystarczy porównać sobie sposób pisania osCommerce z takim projektem jak Magento…
BTM. ...oddzielanie tysięcy (spacja, czy przecinek), pozycja znaku waluty, znak precyzji itd. itp. już nie wspominając o datowaniu i innych.
Radzę tylko, żeby za wczasu nabrać dobrych nawyków i tyle. Jak zapadnie w nieświadomej kompetencji wtedy życie i pisanie dużych projektów będzie o wiele łatwiejsze. Dopiero przy pisaniu dużej aplikacji wykorzystującej MVC, ACL, ORM i innych wzorców projektowych okazuje się, że nawyki mają kolosalne znaczenie.
DrLex | #
#32
DrLex – nie chcę mówić „nie ucz ojca…” bo za wielkie guru się nie uznaję. Tak jak mówiłem – true, dla wartości reprezentujących waluty są gotowe klasy do ich poprawnej reprezentacji. Do wyświetlenia liczby nie opłaca się includować całego PEAR czy Zend’a czy inych. A o MVC, database abstraction layerach czy innych pierdołach wiem, i w tym momencie nie ma sensu ich przywoływanie bo już widzę Twoją aplikację do „wyświetl 1.00” przy użyciu MVC ;-)
Są momenty, w których używa się tej, a są momenty w których używa się innych metod – tu się zgodzę. W tym konkretnym przypadku, o którym pisze autor bloga, nie trzeba aż takich kolosów.
BTM | #
#33
BTM, ale przecież z treści notki wynika, że autor nie miał pojęcia, że istnieje coś innego (nawet kolos). Gdyby wiedział, to by nie napisał takiej notki. Równie dobrze wszystko można obejść w assemblerze, skoro tak fajnie jest używać spadków po C++ jak sprintf itd.
DrLex | #
#34
Sorry, ale dalej brniesz moim zdaniem w ślepą uliczkę.
Autor nie chciał wyświetlać walut, chciał wyświetlić liczbę. Nie potrzebna mu do tego obsługa walut w X językach – to tak jakby ktoś w podstawówce zapytał „ile to 2+2?” a Ty odpowiadasz „no wiesz, wystarczy że obliczysz pochodną drugiego stopnia z całki oznaczonej z logarytmu …”. Bez obrazy – ale po pytaniu autora notki widać, że nie jest on oblatany w tematyce, więc podanie mu rozwiązania opierającego się na OOP jest lekko przesadzone.
BTM | #
#35
Jeżeli sprintf jest już po czymś spatkiem to raczej po C.
mina86 | #
#36
@mina86 wolałem użyć C++, bo ktoś mógłby pomyśleć, że to jakaś samotna literka. W każdym razie nie zmienia to faktu, stosowanie tej funkcji w nowoczesnych językach programowania rodzi złe nawyki. No ale trzeba oddać honor tym funkcjom bo bez nich PHP, Perl nie stałyby się tak popularne na początku.
DrLex | #
#37
Wątpię w to, że sprintf jest powodem popularności PHP. Raczej prosta do nauki składnia, brak konieczności kompilacji czy definiowania zmiennych.
Albi | #
#38
Albi, ja się przesiadłem z CGI na PHP właśnie dlatego, ze wszystko wyglądało znajomo. To były czasy, takie hacki można było robić na buforach, że głowa mała.
DrLex | #
#39
Panowie pomijając waszą kłótnię nieźle mnie zjechaliście. Parę lat siedzenia i kodzenia w PHP, przez co mam chujowe nawyki w programowaniu w C/C++, a okazuje się, że nie wiem czym są number_formats.
Prawda jest taka, że gdyby zależało mi na projekcie, który teraz wykonuję pomyślałbym (gdybym w ogóle to znalazł) nad tym co zaproponował DrLex. Niestety jest tak, że od dłuższego czasu mam gdzieś ten projekt (ze swoich względów, nie muszę tłumaczyć) i parę rzeczy muszę rozwiązać natycmiastowo stosują takie, a nie inne, „haki”.
Poza tym stosowanie molocha w postaci Zend Framework trochę się mija z założonym celem. Szczerze mówiąc to wątpię, żeby ktokolwiek robił wielkie halo z powodu kropki (tudzież przecinka) użytego jako separatora w liczbie..
radmen | #
#40
Dla jasności Zend Framework nie musi być molochem. Do swojego projektu możesz użyć tylko i wyłącznie komponentu Locale np. tak:
require_once ‘Zend/Locale.php’;
$locale = new Zend_Locale(‘pl_PL’);
$number = Zend_Locale_Format::toNumber(13547.3678, array(‘precision’ => 2, ‘locale’ => $locale));
DrLex | #
#41
Wiem, ale i tak nie widzę sensu zastosowania Zenda dla tego jednego (jedynego) przypadku.
Żeby było zabawniej, idiota (który sprawdza stan poprawek) twierdzi, że tych zer i tak nie ma widać. Wcześniej nie mógł się zarejestrować (wszędzie wrzucał same jedynki, a była walidacja) i się nadziwił jakto tak, gdzieś musi być błąd..
radmen | #