2016-12-19 13 views
5

Próbuję wydrukować maks. 4 cyfry po przecinku w C++ (Korzystanie ze strumieni). Więc jeśli liczba nie potrzebuje 4 cyfr po przecinku, chcę, żeby używała tylko liczby dziesiętnej, której faktycznie potrzebuje.Wydrukuj maks. 4 miejsca dziesiętne

Przykłady:

1.12345 -> 1.1234 
1.0  -> 1 
1.12  -> 1.12 
1.12345789 -> 1.1234 
123.123 -> 123.123 
123.123456 -> 123.1234 

Próbowałem std::setprecision(4) ale ustawia liczbę cyfr znaczących i zawodzi w przypadku testu:

123.123456 gives 123.1 

Próbowałem też dając std::fixed wraz z std::setprecision(4) ale daje ustalona liczba cyfr po przecinku, nawet jeśli nie jest potrzebna:

1.0 gives 1.0000 

Wygląda na to, że std::defaultfloat jest tym, czego potrzebuję, a nie naprawionym ani wykładniczym. Wydaje się jednak, że nie drukuje on liczby cyfr po przecinku i ma tylko opcję dla cyfr znaczących.

+4

Wymagałoby to kodu niestandardowego, pracującego nad BCD lub ciągiem znaków przedstawiającym drukowaną wartość. Należy pamiętać, że ponieważ podstawowa reprezentacja liczby zmiennoprzecinkowej jest binarna, niekoniecznie jest to dokładna reprezentacja binarna (powiedzmy) 123.123. Jeśli pokazałeś wystarczająco dużo miejsc po przecinku, coś w stylu 'double x = 123.123; cout << x' może wypisać coś takiego jak '123.1230000001'. Dlatego sugerowałbym napisanie funkcji, która konwertuje double do ciągu znaków z czterema miejscami po przecinku, a następnie usuwa wszelkie końcowe zera za miejscem dziesiętnym, zanim zwróci ciąg znaków. – Simon

+0

Twoje przykłady nie pasują do opisu problemu. Patrząc na te przykłady, bardziej przypominasz nie więcej niż 4 miejsca po przecinku, bez żadnych końcowych zer. To z pewnością nie to samo, co dokładnie 4 miejsca dziesiętne. Poza tym, jak zauważył Simon, biorąc pod uwagę charakter reprezentacji wartości zmiennoprzecinkowych IEEE, będziesz musiał przedstawić lepszą specyfikację tego, co oznacza słowo "potrzebuje cyfry" *. – IInspectable

+2

[Co każdy informatyk powinien wiedzieć o arytmetyki zmiennoprzecinkowej] (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) to prawdopodobnie wymagane czytanie. – IInspectable

Odpowiedz

4

Możemy to zrobić za pomocą std::stringstream i std::string. Przekazujemy double do strumienia, formatując go tak, jak gdybyśmy wysłali go do cout. Następnie sprawdzamy łańcuch, który otrzymujemy ze strumienia, aby zobaczyć, czy istnieją końcowe zera. Jeśli się ich pozbędziemy. Kiedy to zrobimy, sprawdzamy, czy zostaliśmy pozostawieni z kropką dziesiętną, a jeśli tak, to i my się tego pozbędziemy. Można użyć coś takiego:

int main() 
{ 
    double values[] = { 1.12345, 1.0, 1.12, 1.12345789, 123.123, 123.123456, 123456789, 123.001 }; 
    std::vector<std::string> converted; 
    for (auto e : values) 
    { 
     std::stringstream ss; 
     ss << std::fixed << std::setprecision(4) << e; 
     std::string value(ss.str()); 
     if (value.find(".") != std::string::npos) 
     { 
      // erase trailing zeros 
      while (value.back() == '0') 
       value.erase(value.end() - 1); 
      // if we are left with a . at the end then get rid of it 
      if (value.back() == '.') 
       value.erase(value.end() - 1); 
      converted.push_back(value); 
     } 
     else 
      converted.push_back(value); 
    } 
    for (const auto& e : converted) 
     std::cout << e << "\n"; 
} 

Które gdy wykonane w running example daje

1.1235 
1 
1.12 
1.1235 
123.123 
123.1235 
123456789 
123.001 
1

Korzystanie odpowiedź od here wraz z niestandardowych logiki do usuwania zer i punkt:

#include <iostream> 
#include <iomanip> 
#include <sstream> 
#include <string> 
#include <vector> 
#include <iterator> 
#include <algorithm> 

std::string remove_zeros(std::string numberstring) 
{ 
    auto it = numberstring.end() - 1; 
    while(*it == '0') { 
     numberstring.erase(it); 
     it = numberstring.end() - 1; 
    } 
    if(*it == '.') numberstring.erase(it); 
    return numberstring; 
} 

std::string convert(float number) 
{ 
    std::stringstream ss{}; 
    ss << std::setprecision(4) << std::fixed << std::showpoint << number; 
    std::string numberstring{ss.str()}; 
    return remove_zeros(numberstring); 
} 

int main() 
{ 
    const float values[]{1.12345, 1.0, 1.12, 1.12345789, 147323.123, 123.123456}; 
    for(auto i : values) 
     std::cout << convert(i) << '\n'; 
} 

produkuje:

1.1235 
1 
1.12 
1.1235 
147323.125 
123.1235 
Powiązane problemy