Ciągle napotykam specyfikatory formatu dla rodziny funkcji printf (). Chcę móc wydrukować podwójną (lub zmiennoprzecinkową) z maksymalną podaną liczbą cyfr po przecinku. Jeśli używam:
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
dostaję
359.013
359.010
Zamiast pożądanego
359.013
359.01
Czy ktoś może mi pomóc?
Odpowiedzi:
Nie można tego zrobić za pomocą normalnych
printf
specyfikatorów formatu. Najbliższe możesz uzyskać:ale „.6” to całkowita szerokość liczbowa, więc
niszczy to.
To, co możesz zrobić, to zmienić
sprintf("%.20g")
liczbę w buforze ciągów, a następnie manipulować łańcuchem tak, aby zawierał tylko N znaków po przecinku.Zakładając, że twoja liczba znajduje się w zmiennej num, poniższa funkcja usunie wszystkie
N
cyfry z wyjątkiem pierwszych miejsc po przecinku, a następnie usunie końcowe zera (i kropkę dziesiętną, jeśli wszystkie były zerami).Jeśli nie jesteś zadowolony z aspektu obcinania (który zamieniłby się
0.12399
w0.123
zamiast zaokrąglać go0.124
), możesz faktycznie skorzystać z funkcji zaokrąglania już udostępnionych przezprintf
. Wystarczy wcześniej przeanalizować liczbę, aby dynamicznie utworzyć szerokości, a następnie użyć ich do przekształcenia liczby w ciąg:W
nDecimals()
tym przypadku chodzi o poprawne obliczenie szerokości pól, a następnie sformatowanie liczby przy użyciu ciągu formatu na tej podstawie. Uprząż testowamain()
pokazuje to w akcji:Po uzyskaniu prawidłowo zaokrąglonej wartości możesz ponownie przekazać ją,
morphNumericString()
aby usunąć końcowe zera, po prostu zmieniając:w:
(lub wywołanie
morphNumericString
na końcu,nDecimals
ale w takim przypadku prawdopodobnie po prostu połączyłbym te dwie funkcje w jedną funkcję), a otrzymasz:źródło
.
W niektórych ustawieniach miejsce dziesiętne jest w rzeczywistości,
przecinkiem.atof
tę samą wartość.0.10000000000000000555
będzie0.1
po usunięciu . Problem może pojawić się, jeśli masz wartość nieco niższą, na przykład jeśli najbliższa reprezentacja42.1
była42.099999999314159
. Jeśli naprawdę chcesz sobie z tym poradzić, prawdopodobnie będziesz musiał zaokrąglić na podstawie ostatniej usuniętej cyfry, a nie skrócić.printf
funkcji-podobnych, ponieważ obsługują one już parametry dynamiczne (*
znak specjalny): na przykładprintf("%*.*f", total, decimals, x);
wyprowadza liczbę z dynamicznie określoną całkowitą długością pola i miejscami dziesiętnymi.Aby pozbyć się końcowych zer, należy użyć formatu „% g”:
Po pewnym wyjaśnieniu pytania, że pomijanie zer nie jest jedyną rzeczą, o którą pytano, ale wymagane było również ograniczenie wyjścia do trzech miejsc po przecinku. Myślę, że nie można tego zrobić za pomocą samych ciągów formatu sprintf. Jak zauważył Pax Diablo , manipulacja strunami byłaby wymagana.
źródło
Podoba mi się odpowiedź R. nieco poprawiona:
„1000” określa precyzję.
Moc do zaokrąglenia 0,5.
EDYTOWAĆ
Ok, ta odpowiedź była edytowana kilka razy i zgubiłem to, o czym myślałem kilka lat temu (i pierwotnie nie spełniała wszystkich kryteriów). Oto nowa wersja (która spełnia wszystkie kryteria i poprawnie obsługuje liczby ujemne):
I przypadki testowe:
A wynik testów:
Teraz wszystkie kryteria są spełnione:
Niestety ta odpowiedź jest dwuwierszowa, ponieważ
sprintf
nie zwraca ciągu.źródło
Wyszukuję w ciągu (zaczynając od prawej strony) pierwszy znak w zakresie
1
do9
(wartość ASCII49
-57
), a następnienull
(ustawiany na0
) każdy znak na prawo od niego - patrz poniżej:źródło
A co z czymś takim (może zawierać błędy zaokrąglania i problemy z wartością ujemną, które wymagają debugowania, pozostawione jako ćwiczenie dla czytelnika):
Jest trochę programowy, ale przynajmniej nie zmusza cię do manipulacji na ciągach znaków.
źródło
Proste rozwiązanie, ale wykonuje swoje zadanie, przypisuje znaną długość i precyzję oraz pozwala uniknąć możliwości przejścia do formatu wykładniczego (co jest ryzykiem, gdy używasz% g):
Dodaj lub usuń „inne”, jeśli chcesz mieć maksymalnie 2 miejsca po przecinku; 4 miejsca po przecinku; itp.
Na przykład, jeśli chcesz 2 miejsca po przecinku:
Jeśli chcesz określić minimalną szerokość, aby zachować wyrównanie pól, zwiększaj w razie potrzeby, na przykład:
Możesz również przekonwertować to na funkcję, w której podajesz żądaną szerokość pola:
źródło
d = 0.0001
: thenfloor(d)
is0
, więc różnica jest większa niż 0,000001, więcDoubleEquals
jest false, więc nie użyje"%.0f"
specyfikatora: zobaczysz końcowe zera z"%*.2f"
lub"%*.3f"
. Więc to nie odpowiada na pytanie.Znalazłem problemy w niektórych opublikowanych rozwiązaniach. Złożyłem to na podstawie odpowiedzi powyżej. Wydaje mi się, że to działa.
źródło
Niektóre z rozwiązań, które otrzymały najwyższe głosy, sugerują specyfikator
%g
konwersjiprintf
. To jest złe, ponieważ są przypadki, w których%g
wytworzy notację naukową. Inne rozwiązania wykorzystują matematykę do drukowania żądanej liczby cyfr dziesiętnych.Myślę, że najłatwiejszym rozwiązaniem jest użycie
sprintf
ze specyfikatorem%f
konwersji i ręczne usunięcie końcowych zer i ewentualnie przecinka dziesiętnego z wyniku. Oto rozwiązanie C99:Zauważ, że znaki użyte jako cyfry i separator dziesiętny zależą od aktualnych ustawień narodowych. W powyższym kodzie przyjęto ustawienia regionalne C lub angielski (USA).
źródło
Oto moja pierwsza próba odpowiedzi:
Znane błędy: Możliwe przepełnienie bufora w zależności od formatu. Jeśli "." występuje z innego powodu niż% f może wystąpić zły wynik.
źródło
Dlaczego po prostu tego nie zrobić?
źródło
Niewielkie różnice w powyższym:
Kod tutaj:
Nadal ma potencjał do przepełnienia, więc bądź ostrożny; P
źródło
Powiedziałbym, że powinieneś użyć
printf("%.8g",value);
Jeśli używasz
"%.6g"
, nie otrzymasz żądanego wyniku dla niektórych liczb, takich jak 32.230210, powinno się wydrukować,32.23021
ale drukuje32.2302
źródło
Twój kod zaokrągla do trzech miejsc po przecinku ze względu na „.3” przed f
Tak więc, jeśli druga linia została zaokrąglona do dwóch miejsc po przecinku, należy to zmienić na:
Ten kod da pożądane wyniki:
* Zauważ, że jest to założenie, że już drukujesz w oddzielnych wierszach, jeśli nie, to poniższe uniemożliwiają drukowanie w tej samej linii:
Poniższy kod źródłowy programu był moim testem dla tej odpowiedzi
źródło