Powiedzmy, że mamy 0.33
, musimy wydrukować 1/3
.
Jeśli mamy 0.4
, musimy wydrukować 2/5
.
Chodzi o to, aby uczynić ją czytelną dla człowieka, aby użytkownik zrozumiał „ x części z y ” jako lepszy sposób rozumienia danych.
Wiem, że wartości procentowe są dobrym zamiennikiem, ale zastanawiałem się, czy istnieje prosty sposób na zrobienie tego?
algorithm
language-agnostic
numbers
Swaroop CH
źródło
źródło
.33
=>"1/3"
dotyczy mnie; Spodziewałbym się.33
=>"33/100"
. Zakładam, że miałeś na myśli.33...
oczywiście, ale ujawnia to problem z pytaniem - zanim będziemy mogli zdecydować się na algorytm, musimy zdecydować o oczekiwanym zachowaniu. Odpowiedź @ Debilskiego w Pythonie używa.limit_denominator()
domyślnego maksymalnego mianownika 10 ^ 7; chyba dobry domyślny w praktyce, ale to nadal może wprowadzać błędy, jeśli nie jesteś ostrożny, i robi zwrot"33/100"
w.33
sprawie.Odpowiedzi:
Znalazłem racjonalne przybliżenie Davida Eppsteina do danego kodu C liczby rzeczywistej, które jest dokładnie tym, o co prosisz. Opiera się na teorii ułamków ciągłych i jest bardzo szybki i dość zwarty.
Użyłem wersji tego dostosowanych do określonych limitów licznika i mianownika.
źródło
Począwszy od Pythona 2.6 jest
fractions
moduł.(Cytując z dokumentów).
źródło
language agnostic
ialgorithm
tagów odpowiada Twojej odpowiedzi?Jeśli wynik ma dać czytelnikowi szybkie wrażenie kolejności wyniku, nie ma sensu zwracać czegoś takiego jak "113/211", więc wyjście powinno ograniczać się do używania liczb jednocyfrowych (i może 1 / 10 i 9/10). Jeśli tak, możesz zauważyć, że istnieje tylko 27 różnych frakcji.
Ponieważ matematyka będąca podstawą generowania wyniku nigdy się nie zmieni, rozwiązaniem może być po prostu zaprogramowanie na stałe drzewa wyszukiwania binarnego, tak aby funkcja wykonywała co najwyżej porównania log (27) ~ = 4 3/4. Oto przetestowana wersja kodu w C.
źródło
1/1000
jest to również bardzo czytelne dla człowieka, ale powyższy algorytm dałby tylko bardzo zgrubne1/10
przybliżenie; Wierzę, że można wprowadzić usprawnienia w zakresie której po ludzku czytelne mianowniki można wybrać z, i / lub dodatek<
,>
,<<
,>>
przedrostki, aby dać wyobrażenie o chropowatość zbliżenia.Oto link wyjaśniający matematykę związaną z zamianą ułamka dziesiętnego na ułamek:
http://www.webmath.com/dec2fract.html
A oto przykładowa funkcja pokazująca, jak to zrobić za pomocą VB (z www.freevbcode.com/ShowCode.asp?ID=582):
(Z wyszukiwania w Google: zamień ułamek dziesiętny na ułamek, zamień kod dziesiętny na ułamkowy)
źródło
Możesz przeczytać Co każdy informatyk powinien wiedzieć o arytmetyce zmiennoprzecinkowej .
Będziesz musiał określić pewną precyzję, mnożąc przez dużą liczbę:
wtedy możesz zrobić ułamek:
i zmniejsz przez GCD ...
ale nie ma sposobu, aby usunąć zamierzony ułamek. Zamiast tego możesz zawsze chcieć używać ułamków w całym kodzie - pamiętaj tylko, aby zmniejszyć ułamki, kiedy możesz, aby uniknąć przepełnienia!
źródło
Oto wersje kodu VB w języku Perl i Javascript sugerowane przez devinmoore:
Perl:
I prawie identyczny javascript:
źródło
Wdrożenie AC #
źródło
Drzewo Sterna-Brocota powoduje dość naturalny sposób aproksymacji rzeczywistych numerów od frakcji o prostych mianownika.
źródło
Po części problem polega na tym, że tak wielu ułamków nie można łatwo zinterpretować jako ułamków. Np. 0,33 to nie 1/3, to 33/100. Ale jeśli pamiętasz swoje szkolenie w szkole podstawowej, istnieje proces zamiany wartości dziesiętnych na ułamki, jednak jest mało prawdopodobne, aby dało ci to, czego chcesz, ponieważ przez większość czasu liczby dziesiętne nie są przechowywane jako 0,33, ale 0,329999999999998 lub inne.
Zrób sobie przysługę i nie przejmuj się tym, ale jeśli potrzebujesz, możesz wykonać następujące czynności:
Pomnóż oryginalną wartość przez 10, aż usuniesz część ułamkową. Zachowaj tę liczbę i użyj jej jako dzielnika. Następnie wykonaj serię uproszczeń, szukając wspólnych mianowników.
Więc 0,4 byłoby 4/10. Następnie szukałbyś wspólnych dzielników zaczynających się od małych wartości, prawdopodobnie liczb pierwszych. Zaczynając od 2, zobaczysz, czy 2 dzieli równo licznik i mianownik, sprawdzając, czy dolna granica dzielenia jest taka sama jak sama dzielenie.
Więc 5 nie dzieli równo 2. Więc sprawdzasz następną liczbę, powiedz 3. Robisz to, aż trafisz na pierwiastek kwadratowy z mniejszej liczby lub powyżej niego.
Po wykonaniu tej czynności potrzebujesz
źródło
To nie jest „algorytm”, tylko rozwiązanie Pythona: http://docs.python.org/library/fractions.html
źródło
"Powiedzmy, że mamy 0,33, musimy wypisać" 1/3 "."
Jaką precyzję oczekuje się od „rozwiązania”? 0,33 nie jest równe 1/3. Jak rozpoznajesz „dobrą” (łatwą do odczytania) odpowiedź?
Bez względu na wszystko, możliwym algorytmem może być:
Jeśli spodziewasz się znaleźć najbliższy ułamek w postaci X / Y, w której Y jest mniejsze niż 10, możesz zapętlić wszystkie 9 możliwych Y, dla każdego Y obliczyć X, a następnie wybrać najbardziej dokładny.
źródło
Myślę, że najlepszym sposobem na to jest najpierw przekonwertowanie wartości zmiennoprzecinkowej na reprezentację ascii. W C ++ możesz użyć ostringstream lub w C możesz użyć sprintf. Oto, jak by to wyglądało w C ++:
Podobne podejście można zastosować w przypadku prostego C.
Następnie musisz sprawdzić, czy ułamek jest najniższy. Ten algorytm da dokładną odpowiedź, tj. 0,33 da wynik „33/100”, a nie „1/3”. Jednak 0,4 dałoby „4/10”, co po zredukowaniu do najniższych wartości to „2/5”. To może nie być tak potężne jak rozwiązanie EppStein, ale uważam, że jest to prostsze.
źródło
Wbudowane rozwiązanie w R:
Używa metody ciągłego ułamka i ma opcjonalne
cycles
imax.denominator
argumenty do dostosowywania precyzji.źródło
library(numbers)
icontFrac(0.6666)
; aby uzyskać żądany łańcuch wyjściowy:paste(contFrac(0.666, tol=1e-03)$rat, collapse="/")
Musisz dowiedzieć się, jaki poziom błędu chcesz zaakceptować. Nie wszystkie ułamki dziesiętne sprowadzą się do ułamka prostego. Prawdopodobnie wybrałbym łatwo podzielną liczbę, na przykład 60, i obliczyłbym, ile sześćdziesiątych jest najbliżej wartości, a następnie uprościłbym ułamek.
źródło
Możesz to zrobić w dowolnym języku programowania, wykonując następujące czynności:
Przykład: 0,2 = 0,2 x 10 ^ 1/10 ^ 1 = 2/10 = 1/5
Można to więc odczytać jako „1 część z 5”
źródło
Jednym z rozwiązań jest po prostu zapisanie wszystkich liczb jako liczb wymiernych. Istnieją biblioteki do arytmetyki liczb wymiernych (np. GMP ). Jeśli używasz języka OO, możesz po prostu użyć biblioteki klas liczb wymiernych, aby zastąpić swoją klasę liczb.
Programy finansowe, między innymi, używałyby takiego rozwiązania, aby móc wykonywać dokładne obliczenia i zachować precyzję, którą można stracić przy użyciu zwykłego float.
Oczywiście będzie to dużo wolniejsze, więc może nie być dla ciebie praktyczne. Zależy od tego, ile obliczeń musisz wykonać i jak ważna jest dla Ciebie precyzja.
źródło
W powszechnym przypadku jest to błędne, ponieważ 1/3 = 0,3333333 = 0. (3) Ponadto nie można dowiedzieć się z sugerowanych powyżej rozwiązań, czy ułamek dziesiętny można zamienić na ułamek z określoną dokładnością, ponieważ wynik jest zawsze ułamkowy.
ALE, proponuję moją wszechstronną funkcję z wieloma opcjami opartymi na idei nieskończonych szeregów geometrycznych , w szczególności na formule:
Na początku ta funkcja próbuje znaleźć okres ułamka w reprezentacji ciągu. Następnie stosuje się opisaną powyżej formułę.
Kod liczb wymiernych jest zapożyczony z implementacji liczb wymiernych Stephena M. McKameya w C #. Mam nadzieję, że przeniesienie mojego kodu na inne języki nie będzie trudne.
Oto kilka przykładów zastosowań:
Twoja sprawa z przycinaniem części zerowej prawej części:
Demostracja w minionym okresie:
Zaokrąglenie na końcu:
Najciekawszy przypadek:
Inne testy i kod każdy może znaleźć w mojej bibliotece MathFunctions na github .
źródło
Ruby ma już wbudowane rozwiązanie:
W Railsach atrybuty liczbowe ActiveRecord można również konwertować:
źródło
Odpowiedz w C ++, zakładając, że masz klasę „BigInt”, która może przechowywać liczby całkowite o nieograniczonym rozmiarze.
Możesz zamiast tego użyć „unsigned long long”, ale będzie to działać tylko dla niektórych wartości.
BTW, GetRational (0.0) zwróci „+0/1”, więc możesz zająć się tym przypadkiem osobno.
PS: Używam tego kodu w mojej własnej klasie „RationalNum” od kilku lat i został gruntownie przetestowany.
źródło
while
pętli jest ograniczony rozmiaremdouble
, który wynosi zazwyczaj 64 bity. Nie zależy więc od początkowej wartości input (val
).GCD
Funkcja, jednak nie zależy od tej wartości, choć zwykle jest zbieżny do rozwiązania dość szybko. Czy to możliwe, że nie zaimplementowałeś tej funkcji poprawnie?unsigned long long
zamiastBigInt
, to niekoniecznie da to poprawny wynik dla każdej wartości wejściowej ... Ale nawet w tym scenariuszu kod nie jest powinien „wejść w bardzo długą pętlę”.GCD
funkcja nie jest poprawnie zaimplementowana. Czy sprawdziłeś, czy kod działa przez długi czas podczaswhile
pętli, czy po niej? Sprawdzę wartość 1.33333, żeby zobaczyć, co się za tym kryje. Dzięki.Ten algorytm autorstwa Iana Richardsa / Johna Kennedy'ego nie tylko zwraca ładne ułamki, ale także działa bardzo dobrze pod względem szybkości. To jest kod C # wzięty z tej odpowiedzi przeze mnie.
Obsługuje wszystkie
double
wartości z wyjątkiem specjalnych wartości, takich jak NaN i +/- nieskończoność, które musisz dodać w razie potrzeby.Zwraca a
new Fraction(numerator, denominator)
. Zastąp własnym typem.Więcej przykładowych wartości i porównanie z innymi algorytmami można znaleźć tutaj
Przykładowe wartości zwracane przez ten algorytm:
źródło
Będziesz mieć dwa podstawowe problemy, które to utrudnią:
1) Liczba zmiennoprzecinkowa nie jest dokładną reprezentacją, co oznacza, że jeśli masz ułamek „x / y”, który daje wartość „z”, algorytm ułamka może zwrócić wynik inny niż „x / y”.
2) Istnieje nieskończenie wiele więcej liczb niewymiernych niż racjonalnych. Liczba wymierna to taka, którą można przedstawić jako ułamek. Istoty irracjonalne, które nie potrafią.
Jednak w tani sposób, ponieważ zmiennoprzecinkowe mają ograniczoną dokładność, zawsze możesz przedstawić to jako jakąś formę frakcji. (Myślę...)
źródło
Ukończono powyższy kod i przekonwertowano go na as3
źródło
Oto szybka i brudna implementacja w javascript, która wykorzystuje podejście brutalnej siły. Wcale niezoptymalizowany, działa w predefiniowanym zakresie ułamków: http://jsfiddle.net/PdL23/1/
Jest to inspirowane podejściem stosowanym przez JPS.
źródło
Jak twierdziło wiele osób, naprawdę nie można przekonwertować liczby zmiennoprzecinkowej z powrotem na ułamek (chyba że jest bardzo dokładny, np. 0,25). Oczywiście możesz stworzyć rodzaj wyszukiwania dla dużej tablicy ułamków i użyć jakiejś logiki rozmytej, aby uzyskać wynik, którego szukasz. Znowu nie byłoby to dokładne i musiałbyś zdefiniować dolne granice tego, jak duży ma być mianownik.
.32 <x <.34 = 1/3 lub coś w tym rodzaju.
źródło
Oto implementacja dla ruby http://github.com/valodzka/frac
źródło
Natknąłem się na wyjątkowo eleganckie rozwiązanie Haskella wykorzystujące anamorfizm. To zależy od pakietu schematów rekurencji .
Jeśli wypróbujesz to w ghci, to naprawdę działa!
źródło