Chcę usunąć cyfry z pływaka, aby mieć stałą liczbę cyfr po kropce, na przykład:
1.923328437452 -> 1.923
Muszę wyprowadzić jako ciąg do innej funkcji, a nie drukować.
Chcę też zignorować utracone cyfry, a nie je zaokrąglić.
python
floating-point
Joan Venge
źródło
źródło
Odpowiedzi:
Po pierwsze, funkcja dla tych, którzy chcą po prostu kopiować i wklejać kod:
Dotyczy to Pythona 2.7 i 3.1+. W przypadku starszych wersji nie można uzyskać tego samego efektu „inteligentnego zaokrąglania” (przynajmniej nie bez mnóstwa skomplikowanego kodu), ale zaokrąglanie do 12 miejsc po przecinku przed obcięciem będzie działać przez większość czasu:
Wyjaśnienie
Podstawową metodą jest przekonwertowanie wartości na ciąg z pełną precyzją, a następnie odcięcie wszystkiego poza wymaganą liczbę znaków. Drugi krok jest łatwy; można to zrobić za pomocą manipulacji na łańcuchach
lub
decimal
modułPierwszy krok, konwersja na łańcuch, jest dość trudny, ponieważ istnieje kilka par literałów zmiennoprzecinkowych (tj. Tego, co piszesz w kodzie źródłowym), które tworzą tę samą reprezentację binarną, a mimo to powinny być obcięte w inny sposób. Na przykład rozważmy 0,3 i 0,29999999999999998. Jeśli piszesz
0.3
w programie w języku Python, kompilator koduje go przy użyciu formatu zmiennoprzecinkowego IEEE do sekwencji bitów (zakładając 64-bitową liczbę zmiennoprzecinkową)Jest to wartość najbliższa 0,3, którą można dokładnie przedstawić jako wartość zmiennoprzecinkową IEEE. Ale jeśli piszesz
0.29999999999999998
w programie w Pythonie, kompilator tłumaczy to na dokładnie tę samą wartość . W jednym przypadku miałeś na myśli obcięcie go (do jednej cyfry) jako0.3
, podczas gdy w innym przypadku chciałeś, aby został skrócony jako0.2
, ale Python może udzielić tylko jednej odpowiedzi. Jest to podstawowe ograniczenie Pythona, a właściwie każdego języka programowania bez leniwej oceny. Funkcja obcinania ma dostęp tylko do wartości binarnej przechowywanej w pamięci komputera, a nie do ciągu, który faktycznie wpisałeś w kodzie źródłowym. 1Jeśli zdekodujesz sekwencję bitów z powrotem do liczby dziesiętnej, ponownie używając 64-bitowego formatu zmiennoprzecinkowego IEEE, otrzymasz
więc wpadłaby naiwna implementacja,
0.2
nawet jeśli prawdopodobnie nie tego chcesz. Aby uzyskać więcej informacji na temat błędu reprezentacji zmiennoprzecinkowej, zobacz samouczek języka Python .Bardzo rzadko można pracować z wartością zmiennoprzecinkową, która jest tak bliska okrągłej liczbie, ale celowo nie jest równa tej okrągłej liczbie. Dlatego podczas obcinania prawdopodobnie sensowne jest wybranie „najładniejszej” reprezentacji dziesiętnej spośród wszystkich, które mogą odpowiadać wartości w pamięci. Python 2.7 i nowsze (ale nie 3.0) zawierają wyrafinowany algorytm, który to robi , do którego możemy uzyskać dostęp poprzez domyślną operację formatowania ciągu.
Jedynym zastrzeżeniem jest to, że działa to jak
g
specyfikacja formatu, w tym sensie, że używa notacji wykładniczej (1.23e+4
), jeśli liczba jest wystarczająco duża lub wystarczająco mała. Więc metoda musi wychwycić ten przypadek i obsłużyć go inaczej. Jest kilka przypadków, w których użycief
specyfikacji formatu zamiast tego powoduje problem, na przykład próba skrócenia3e-10
dokładności do 28 cyfr (daje to0.0000000002999999999999999980
), i nie jestem jeszcze pewien, jak najlepiej sobie z nimi poradzić.Jeśli rzeczywiście są pracy z
float
S, które są bardzo zbliżone do okrągłych liczb, ale celowo nie równa się do nich (jak 0.29999999999999998 lub 99.959999999999994), to będzie produkować kilka fałszywych alarmów, to znaczy będziemy okrągłych liczb, które nie chcą zaokrąglone. W takim przypadku rozwiązaniem jest określenie stałej precyzji.Liczba precyzyjnych cyfr, których należy tu użyć, nie ma tak naprawdę znaczenia, musi być tylko wystarczająco duża, aby zapewnić, że jakiekolwiek zaokrąglenia wykonywane podczas konwersji ciągów nie „podbijają” wartości do jej ładnej reprezentacji dziesiętnej. Myślę, że
sys.float_info.dig + n + 2
może wystarczyć we wszystkich przypadkach, ale jeśli nie,2
może to wymagać zwiększenia i nie zaszkodzi to zrobić.We wcześniejszych wersjach Pythona (do 2.6 lub 3.0) formatowanie liczb zmiennoprzecinkowych było dużo bardziej prymitywne i regularnie powodowało takie rzeczy, jak
Jeśli to jest Twoja sytuacja, jeśli nie chcesz korzystać z „nice” reprezentacje dziesiętne do obcinania, wszystko można zrobić (o ile wiem), to wybrać pewną liczbę cyfr, mniej niż pełnej precyzji reprezentowana przez
float
i Round numer do tylu cyfr przed skróceniem go. Typowy wybór to 12,ale możesz to dostosować do używanych liczb.
1 Cóż ... skłamałem. Technicznie, można polecić Python, aby ponownie przeanalizować swój własny kod źródłowy i wyodrębnić część odpowiadającą pierwszego argumentu możesz przekazać do funkcji przycinania. Jeśli ten argument jest literałem zmiennoprzecinkowym, możesz po prostu odciąć go o określoną liczbę miejsc po przecinku i zwrócić to. Jednak ta strategia nie działa, jeśli argument jest zmienną, co czyni ją dość bezużyteczną. Poniższe informacje przedstawiono wyłącznie w celach rozrywkowych:
Uogólnienie tego, aby obsłużyć przypadek, w którym przekazujesz zmienną, wydaje się być utraconą przyczyną, ponieważ musiałbyś prześledzić wstecz przez wykonanie programu, aż znajdziesz literał zmiennoprzecinkowy, który nadał zmiennej jej wartość. Jeśli w ogóle istnieje. Większość zmiennych zostanie zainicjowana na podstawie danych wejściowych użytkownika lub wyrażeń matematycznych, w takim przypadku wystarczy reprezentacja binarna.
źródło
applymap()
.). Może jest sposób, aby cała operacja była bardziej wydajna, ale to byłaby kwestia osobnego pytania.Zobacz dokumentację Pythona na temat standardowych typów . Musisz trochę przewinąć w dół, aby przejść do funkcji rundy. Zasadniczo druga liczba mówi, do ilu miejsc po przecinku należy ją zaokrąglić.
źródło
Wynik
round
jest float, więc uważaj (przykład pochodzi z Pythona 2.6):Lepiej będzie, jeśli użyjesz sformatowanego ciągu:
źródło
round(1.23456, 3)
jest1.235
i nie jest1.2350000000000001
źródło
2
, będziesz mieć kropkę dziesiętną.
na końcu ciągu - myślę, że nie jest to dobre rozwiązanie.Na mój znak zachęty Pythona 2.7:
>>> int(1.923328437452 * 1000)/1000.0 1.923
źródło
Prosty skrypt w Pythonie -
źródło
To powinno działać. Powinien dać ci skrócenie, którego szukasz.
źródło
Prawdziwie pytoniczny sposób to zrobić
lub krócej:
Aktualizacja
Zwykle problemem nie jest samo obcinanie liczb zmiennoprzecinkowych, ale niewłaściwe użycie liczb zmiennoprzecinkowych przed zaokrągleniem.
Na przykład:
int(0.7*3*100)/100 == 2.09
.Jeśli jesteś zmuszony używać pływaków (powiedzmy, że przyspieszasz swój kod
numba
), lepiej użyć centów jako „wewnętrznej reprezentacji” cen: (70*3 == 210
) i pomnożyć / podzielić dane wejściowe / wyjściowe.źródło
int(0.7*3*100)/100 == 2.09
. Gdzie poszedł mój 1 cent?ImportError: cannot import name 'D'
, wierzę, że chciał zrobić o nazwie import nie?Tak wiele odpowiedzi udzielonych na to pytanie jest po prostu całkowicie błędnych. Albo zaokrąglają liczby zmiennoprzecinkowe w górę (zamiast skracać), albo nie działają we wszystkich przypadkach.
To jest najlepszy wynik Google, kiedy wyszukuję „Python truncate float”, koncepcja, która jest naprawdę prosta i zasługuje na lepsze odpowiedzi. Zgadzam się z Hatchkinsem, że użycie
decimal
modułu jest pythonowym sposobem na zrobienie tego, więc podaję tutaj funkcję, która moim zdaniem poprawnie odpowiada na pytanie i która działa zgodnie z oczekiwaniami we wszystkich przypadkach.Na marginesie, wartości ułamkowe na ogół nie mogą być dokładnie reprezentowane przez binarne zmienne zmiennoprzecinkowe (zobacz tutaj omówienie tego), dlatego moja funkcja zwraca ciąg.
źródło
Zrobiłem coś takiego:
źródło
Możesz to zrobić:
testowanie:
źródło
Jeśli masz ochotę na matematykę, działa to dla liczb + ve:
źródło
Podczas używania pandy df to działało dla mnie
źródło
Chciałem tylko wspomnieć, że stara sztuczka "make round () z floor ()"
można odwrócić, aby podłoga () z rundy ()
Chociaż obie te zasady łamią liczby ujemne, użycie ich jest mniej niż idealne:
źródło
int (16,5); da to liczbę całkowitą 16, tj. obcięcie, nie będzie w stanie podać liczb dziesiętnych, ale myślę, że możesz to zrobić przez
źródło
Oto prosty sposób:
dla num = 1,923328437452, daje to 1,923
źródło
źródło
Ogólna i prosta funkcja w użyciu:
źródło
W Pythonie 3 jest łatwe obejście problemu. Gdzie wyciąć, zdefiniowałem za pomocą zmiennej pomocy decPlace, aby ułatwić dostosowanie.
Wynik:
Mam nadzieję, że to pomoże.
źródło
źródło
Wariant krótki i łatwy
źródło
Moim zdaniem większość odpowiedzi jest zbyt skomplikowana, a co powiesz na to?
Po prostu wyszukuję indeks „.” i obcinaj według potrzeb (bez zaokrąglania). Konwertuj ciąg na zmiennoprzecinkowy jako ostatni krok.
Lub w twoim przypadku, jeśli otrzymujesz zmiennoprzecinkowy jako dane wejściowe i chcesz, aby łańcuch jako wyjście:
źródło
# podziel i pomnóż przez 10 ** żądanych cyfr
źródło
użyj numpy.round
źródło
Coś na tyle prostego, aby zmieściło się w liście, bez bibliotek ani innych zewnętrznych zależności. W przypadku Pythona> = 3.6 bardzo łatwo jest pisać za pomocą f-strings.
Chodzi o to, aby konwersja ciągów zaokrągliła do jednego miejsca więcej niż potrzebujesz, a następnie odcięła ostatnią cyfrę.
Oczywiście zachodzi tutaj zaokrąglanie (mianowicie dla czwartej cyfry), ale zaokrąglenia w pewnym momencie nie da się uniknąć. Jeśli przejście między obcinaniem a zaokrąglaniem jest istotne, oto nieco lepszy przykład:
Bonus: usunięcie zer po prawej stronie
źródło
Podana tutaj podstawowa idea wydaje mi się najlepszym podejściem do tego problemu. Niestety, otrzymała mniej głosów, a późniejsza odpowiedź, która ma więcej głosów, nie jest kompletna (jak zauważono w komentarzach). Miejmy nadzieję, że poniższa implementacja zapewnia krótkie i kompletne rozwiązanie do obcięcia .
który powinien zająć się wszystkimi narożnymi skrzynkami znalezionymi tutaj i tutaj .
źródło
Jestem również nowicjuszem w Pythonie i po skorzystaniu z kilku kawałków tutaj, oferuję moje dwa centy
str (int (time.time ())) weźmie epokę czasu jako int i skonwertuje ją na łańcuch i połączy z ... str (datetime.now (). microsecond) [: 3], która zwraca tylko mikrosekundy, konwertuje ciągnąć i obcinać do pierwszych 3 znaków
źródło
źródło
Jeśli masz na myśli drukowanie, to powinno działać:
źródło