0
#include <iostream>
using namespace std;

int main()
{
    cout.precision(50);
    cout<<"Anmol's Square Root Calculator!"<<endl;
    cout<<""<<endl;
    cout << "This program will compute the square root\n";
    cout << "of a number using the Babylonian algorithm!\n";
    cout<<""<<endl;
    cout<<"Only positive numbers work with this algorithm!"<<endl;
    cout<<""<<endl;
    cout<<"All cycle #1 approximate square roots are guessed\n"<<"using 1 as the first        approximate."<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;



    char playAgain='y';
    while (playAgain !='n') 
    {
        int count(25), cycle(1);
        double guess, sqrt, num; 
        cout << "Please enter the number you would like to compute the square root of: ";
        cin >> num;
        cout<<""<<endl;

        do {
            if (num <= 0)
            {
                cout<<""<<endl;
                cout<<"Invalid input. Please re-enter a valid number: ";
                cin >> num;
                cout<<""<<endl;
            }
        } while (num <= 0);

        cout<<""<<endl;
        cout<<""<<endl;
        cout<<""<<endl;

        for (guess=1; count!=0; count--)
        { 
            guess =(guess + (num/guess))/2;
            cout<<""<<endl;
            cout<<"Cycle "<<cycle<<" Aproximate: "<<guess<<endl;
            sqrt = guess;

            cycle++;
        }

        cout<<""<<endl;

        cout << "The square root of "<< num << " is " << sqrt<<"!"<<endl;;
        cout <<""<< endl;

        do { 
            cout <<""<<endl;
            cout << "Would you like to calculate again? (y/n): ";
            cin >> playAgain;
            cout <<" "<<endl;
            do { 
                cout <<""<<endl;
                if ((playAgain !='y' && playAgain !='n'))
                {
                    cout << "Invalid input. Only y/n: ";
                    cin >> playAgain;
                    cout <<" "<<endl;
                } 
            } while (playAgain !='y' && playAgain !='n');

        } while (playAgain !='y' && playAgain !='n');

    }

    cout<<"Thank you for using a program made by Anmol Sethi!"<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cin.get();
    return 0;
}

在我的数学课上,我们正在学习平方根。根据我的老师的说法,只有使用计算器或表格才能找到平方根,这显然是错误的,因为计算器需要一种计算 sqrt 的方法。经过广泛的研究,我使用巴比伦算法编写了这段代码。但是我面临一个问题在这段代码中,我专门将小数的精度设置为 15。但是它输出的数字是小数点后 12 位。但在这段代码中,它以小数点后 15 位输出。

#include <iostream>
using namespace std;

int main()
{
    cout.precision(18);
    cout<<"Anmol's Square Root Calculator!"<<endl;
    cout<<""<<endl;
    cout << "This program will compute the square root\n";
    cout << "of a number using the Babylonian algorithm!\n";
    cout<<""<<endl;
    cout<<"Only positive numbers work with this algorithm!"<<endl;
    cout<<""<<endl;
    cout<<"All cycle #1 approximate square are guessed\n"<<"using 1 as the approximate."<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    char playAgain='y';
    while (playAgain !='n') 
    {
        int count(25), cycle(1);
        double guess(1), sqrt, x, num; 
        cout << "Please enter the number you would like to know the square root of: ";
        cin >> num;
        cout<<""<<endl;

        do {
            if (num <= 0)
            {
                cout<<""<<endl;
                cout<<"Invalid input. Please re-enter a valid number: ";
                cin >> num;
                cout<<""<<endl;
            }
        } while (num <= 0);

        cout<<""<<endl;
        cout<<""<<endl;
        cout<<""<<endl;

        while (count > 0)
        {
            x = guess =(guess + (num/guess))/2;
            cout<<""<<endl;
            cout<<"Cycle "<<cycle<<" Aproximate: "<<guess<<endl;
            sqrt = guess;

            count-=1;
            cycle+=1;
        }

        cout<<""<<endl;
        cout<<""<<endl;
        cout<<""<<endl;
        cout << "The sqaure root of "<< num << " is " << sqrt<<"!"<<endl;;
        cout <<""<< endl;

        do { 
            cout <<""<<endl;
            cout << "Would you like to calculate again? (y/n): ";
            cin >> playAgain;
            cout <<" "<<endl;

            do { 
                cout <<""<<endl;
                if ((playAgain !='y' && playAgain !='n'))
                {
                    cout << "Invalid input. Only y/n: ";
                    cin >> playAgain;
                    cout <<" "<<endl;
                } 
            } while (playAgain !='y' && playAgain !='n');

        } while (playAgain !='y' && playAgain !='n');

    }

    cout<<"Thank you for using a program made by Anmol Sethi!"<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cin.get();
    return 0;

}

我很困惑为什么会这样。我试过 cout << fixed << showpoint; 但是当 num 无缘无故输出 15 个零时,它看起来很不愉快。谁能告诉我为什么会发生这种情况以及如何解决它?在书中,我读到使用 for 循环进行算法更有效,所以我想使用 for 而不是 while 循环。我还有第二个问题。为什么我不能超过小数点后 15 位?如果我将精度设置为 30/40,即使在我的计算机计算器中它达到 30/40,它对我的​​输出也没有任何影响。我应该使用另一种整数类型而不是双精度类型吗?

抱歉,如果其中任何一个看起来像一大堵文字 xD。

我急于输入这个,因为我的 atm 是凌晨 12:05。

先谢谢了

ps 我现在会在这个论坛上发很多帖子。大约一年前我经常使用它,但我退出了一段时间的 c++ 编程,因为当我更小的 xD 时我无法进一步理解它。所以我现在正在读一本书,我希望能一直通过控制台应用程序并进入 Windows。如果重要的话,我正在使用 Visual Studio Ultimate 2012。xD

4

1 回答 1

7

首先,欢迎来到 StackOverflow!我敢肯定,当您学习编程时,您会发现它是一种宝贵的资源。也就是说,为了充分利用该网站,遵守该网站的指南非常重要。一般来说,请记住,SO 不是一个论坛,而是一个问答网站,你会做得很好。


一般问题

您发布的代码存在一些问题:

A. 空白

使用空格非常有助于使您的代码对其他程序员和您自己都 清晰易懂。用 Tab 表示范围(写作

bool condition = ...
if (condition) {
    action();
}

而不是

bool condition = ...
if (condition) {
action()
}

这并不表示操作范围)显着提高了可读性,尤其是当您发布的代码中存在多个嵌套 范围时。 间距也很重要。

B. 使用cout

1. 与其写作,不如cout << "" << endl简单地写作cout << endl

2.之间 存在差异endl"\n",从您的代码中可以看出您可能知道它们。虽然使用两者的性能特点并不完全相同,但考虑到现阶段肯定会过早优化。坚持endl这种日志记录更具可读性。而不是

cout << "All cycle #1 approximate square are guessed\n" << "using 1 as the approximate." << endl;

最好写

cout << "All cycle #1 approximate square are guessed" << endl << "using 1 as the approximate." << endl;

在这种情况下。

3. 如果您在一行代码中插入的int超过了合适的范围(此代码,cout

cout << "This line of code is longer than feels comfortable." << endl << "It would be much more pleasant to break this into several lines so that I don't need to scroll to the right to view the whole thing." << endl;

例如,对于一行来说太长了),而不是像您的代码中那样,

cout << "Anmol's Square Root Calculator!" << endl;
cout << endl;
cout << "This program will compute the square root\n";
cout << "of a number using the Babylonian algorithm!\n";
cout << endl;
cout << "Only positive numbers work with this algorithm!" << endl;
cout << endl;
cout << "All cycle #1 approximate square are guessed\n" << "using 1 as the approximate." << endl;
cout << endl;
cout << endl;
cout << endl;

cout多次使用插入运算符,你可以写

cout << "Anmol's Square Root Calculator!" << endl
     << endl
     << "This program will compute the square root" << endl
     << "of a number using the Babylonian algorithm!" << endl
     << endl
     << "Only positive numbers work with this algorithm!" << endl
     << endl
     << "All cycle #1 approximate square are guessed"  << endl
     << "using 1 as the approximate." << endl
     << endl
     << endl
     << endl;

C. 模块化

你所有的代码都在main(). 即使有这么短的程序,这仍然会妨碍可读性。更重要的是,这意味着您不能在其他地方重用您在此程序中创建的功能。

一个好的方法是将您的程序分解成单独的组件。在这个程序中,您有以下设置:

show a greeting
do {
    get number from user
    compute the squareroot of that number while logging
    show the user the squareroot
    ask the user if they want to do another computation
} while the user wants the program to keep running
show a farewell

此时,您可以为每个步骤编写函数。我在这里“编写”的函数摘自您的代码,稍作修改。

打印到屏幕

向用户显示问候和告别的功能是最简单的,因为它们(几乎)只需要使用cout

void showGreeting()
{
    cout << "Anmol's Square Root Calculator!" << endl
         << endl
         << "This program will compute the square root" << endl
         << "of a number using the Babylonian algorithm!" << endl
         << endl
         << "Only positive numbers work with this algorithm!" << endl
         << endl
         << "All cycle #1 approximate square are guessed"  << endl
         << "using 1 as the approximate." << endl
         << endl
         << endl
         << endl;
}

void showFarewell()
{
    cout << "Thank you for using a program made by Anmol Sethi!" << endl
         << endl
         << endl
         << endl;
    cin.get();
}

获取用户输入

接下来我们需要一个函数来从用户那里获取一个数字

double getInputNumber()
{
    double num = 0.0f;

    cout << "Please enter the number you would like to compute the square root of: ";
    cin >> num;
    cout << endl;

    do {
        if (num <= 0)
        {
            cout << endl
                 << "Invalid input. Please re-enter a valid number: ";
            cin >> num;
            cout << endl;
        }
    } while (num <= 0);

    cout << endl
         << endl
         << endl;

    return num;
}

此外,我们需要确定用户是否希望程序再次运行。从程序的角度(的角度main)来看,这在很大程度上是一个布尔问题:我们应该调用某个函数,它应该返回trueor false。但是,在函数中,我们正在与用户进行交互,因此使用'y'and'n'是理想的(至少对于说英语的用户而言);

bool getRunAgain()
{
    bool choice = false;

    char playAgain = 'n';
    do { 
        cout << endl
             << "Would you like to calculate again? (y/n): ";
        cin >> playAgain;
        cout << endl;
        do { 
            cout << endl;
            if ((playAgain !='y' && playAgain !='n'))
            {
                cout << "Invalid input. Only y/n: ";
                cin >> playAgain;
                cout << endl;
            } 
        } while (playAgain !='y' && playAgain !='n');
    } while (playAgain !='y' && playAgain !='n');

    if (playAgain == 'y') {
        choice = true;
    } else /*if (playAgain == 'n')*/ {//At this, playAgain is either 'y' or 'n'.  So if it's not 'y', it's 'n'.
        choice = false;
    }
    return choice;
}

由于将此代码重写为函数,因此更容易看到这里正在完成的工作超出了必要的范围:考虑外部do...while循环。它的重复条件是playAgain !='y' && playAgain !='n'。乍一看,这似乎是有道理的:我们需要确保用户输入了“是”或“否”。do...while但请注意,有一个条件完全相同的内部循环。playAgain这意味着除非等于'y'or ,否则内部循环不会退出'n'。因此,当我们离开内部循环时,我们可以确定它playAgain'y'or 'n'。所以我们不需要再次检查它。这允许我们像这样重写函数:

bool getRunAgain()
{
    bool choice = false;

    char playAgain = 'n';
    cout << endl
         << "Would you like to calculate again? (y/n): ";
    cin >> playAgain;
    cout << endl;
    do { 
        cout << endl;
        if ((playAgain !='y' && playAgain !='n'))
        {
            cout << "Invalid input. Only y/n: ";
            cin >> playAgain;
            cout << endl;
        } 
    } while (playAgain !='y' && playAgain !='n');

    if (playAgain == 'y') {
        choice = true;
    } else /*if (playAgain == 'n')*/ {
        choice = false;
    }
    return choice;
}

但是我们在剩下的循环中有类似的情况:

do { 
    cout << endl;
    if ((playAgain !='y' && playAgain !='n'))
    {
        cout << "Invalid input. Only y/n: ";
        cin >> playAgain;
        cout << endl;
    } 
} while (playAgain !='y' && playAgain !='n');

除了cout << endlwhich 不太重要之外,看起来我们根本不想进入循环,除非(playAgain !='y' && playAgain !='n')。这需要while循环而不是do...while循环:

while (playAgain !='y' && playAgain !='n')
{
    cout << "Invalid input. Only y/n: ";
    cin >> playAgain;
    cout << endl;
}

把它放到我们的函数中,我们现在有

bool getRunAgain()
{
    bool choice = false;

    char playAgain = 'n';
    cout << endl
         << "Would you like to calculate again? (y/n): ";
    cin >> playAgain;
    cout << endl;

    while (playAgain !='y' && playAgain !='n')
    {
        cout << "Invalid input. Only y/n: ";
        cin >> playAgain;
        cout << endl;
    }

    if (playAgain == 'y') {
        choice = true;
    } else /*if (playAgain == 'n')*/ {
        choice = false;
    }
    return choice;
}

计算平方根

最后,我们需要一个函数来使用巴比伦算法计算平方根。我们只需要获取您的代码

int count(25), cycle(1);
double guess, sqrt, num; 
cout << "Please enter the number you would like to compute the square root of: ";
cin >> num;
cout << endl;

for (guess=1; count!=0; count--)
{ 
    guess =(guess + (num/guess))/2;
    cout<<""<<endl;
    cout<<"Cycle "<<cycle<<" Aproximate: "<<guess<<endl;
    sqrt = guess;

    cycle++;
}

并将其放入一个接受 double 并返回一个的函数中:

double computeSquareRootBabylonian(double num)
{
    int count(25), cycle(1);
    double guess, sqrt; 

    for (guess = 1; count != 0; count--)
    { 
        guess = (guess + (num/guess))/2;
        cout << endl
             << "Cycle " << cycle << " Aproximate: " << guess << endl;
        sqrt = guess;

        cycle++;
    }
    return sqrt;
}

我们可以在这里停下来,但是有一些更改可以改进该功能。

1. 初始近似值(您正在使用的初始猜测,1)实际上并不是该函数的一部分。调用此函数的代码必须指定该起点:

double computeSquareRootBabylonian
(double num, 
 double initialApproximation)
{
    double approximation, sqrt;
    unsigned int count(25), cycle(1);

    for (approximation = initialApproximation; count != 0; count--)
    {
        approximation =(approximation + (num/approximation))/2;
        cout << endl
             << "Cycle " << cycle << " Aproximate: " << approximation << endl;
        sqrt = approximation;

        cycle++;
    }
    return sqrt;
}

2. 迭代次数(或循环次数,正如您所说的那样)也不是函数的一部分。调用此函数的代码必须指定该数字:

double computeSquareRootBabylonian
(double num, 
 double initialApproximation, 
 unsigned int iterations)
{
    double approximation, sqrt;
    unsigned int iterationsRemaining = iterations;
    unsigned int iteration = 1;

    for (approximation = initialApproximation; iterationsRemaining != 0; iterationsRemaining--)
    {
        approximation =(approximation + (num/approximation))/2;
        cout << endl
             << "Cycle " << iteration << " Aproximate: " << approximation << endl;
        sqrt = approximation;

        iteration++;
    }
    return sqrt;
}

3. 这个for循环很奇怪。这很奇怪,因为您在初始化时初始化了变量guess(我已将其重命名approximation),尽管它不是 “循环变量”。在您的第二段代码中,您使用了

while (count > 0)
{
    guess =(guess + (num/guess))/2;
    cout << endl;
    cout << "Cycle " << cycle << " Aproximate: " << guess << endl;
    sqrt = guess;

    count-=1;
    cycle+=1;
}

反而。这段代码的意图要清楚得多,但是使用标准方式for的循环(在初始化中初始化循环条件所依赖的相同变量,并且在每个循环结束时更改:),其意图会更清楚。在这里迭代的变量是(我称之为),只要它大于 ,它就会从用户指定的迭代次数(参数)中减少。这种情况需要以下 for 循环:for (int i = 0; i < 10; i++)countiterationsRemainingiterations10

for (unsigned int iterationsRemaining = iterations; 
     iterationsRemaining > 0; 
     iterationsRemaining--) 
{
    //...
}

将其代入我们的函数时,我们需要确保仍然初始化approximationinitialApproximation

double computeSquareRootBabylonian
(double num, 
 double initialApproximation,
 unsigned int iterations)
{
    double approximation = initialApproximation;
    unsigned int iteration = 1;
    double sqrt;

    for (unsigned int iterationsRemaining = iterations; 
         iterationsRemaining > 0; 
         iterationsRemaining--) 
    {
        approximation =(approximation + (num/approximation))/2;
        cout << endl
             << "Cycle " << iteration << " Aproximate: " << approximation << endl;
        sqrt = approximation;

        iteration++;
    }
    return sqrt;
}

旁白:更多过早的优化

你写了

在书中,我读到使用 for 循环进行算法更有效,所以我想使用 for 而不是 while 循环。

这不是使用for循环的好理由。您不需要(在合理范围内)对代码进行更改以使其更快,除非您确定它运行得太慢。编写在阅读时有意义的代码更为重要。

4.变量sqrt有什么作用?它重复地approximation赋值给它并从函数中返回,但它返回时的值与 的值相同approximation。出于这个原因删除它相当于过早的优化。但是,调用该变量sqrt表明它是真正的平方根,而不是近似值。出于这个原因,它应该被删除,留给我们

double computeSquareRootBabylonian
(double num, 
 double initialApproximation,
 unsigned int iterations)
{
    double approximation = initialApproximation;
    unsigned int iteration = 1;

    for (unsigned int iterationsRemaining = iterations; 
         iterationsRemaining > 0; 
         iterationsRemaining--) 
    {
        approximation =(approximation + (num/approximation))/2;
        cout << endl
             << "Cycle " << iteration << " Aproximate: " << approximation << endl;

        iteration++;
    }
    return approximation;
}

5. 记录每次迭代的逐次近似值并不是您总是希望平方根函数做的事情。我们应该添加一个参数,允许调用代码指定是否记录近似值:

double computeSquareRootBabylonian
(double num, 
 double initialApproximation,
 unsigned int iterations,
 bool log)
{
    double approximation = initialApproximation;
    unsigned int iteration = 1;

    for (unsigned int iterationsRemaining = iterations; 
         iterationsRemaining > 0; 
         iterationsRemaining--) 
    {
        approximation =(approximation + (num/approximation))/2;
        if (log) 
        {
            cout << endl << "Cycle " << iteration << " Aproximate: " << approximation << endl;
        }
        iteration++;
    }
    return approximation;
}

编写主函数

我们现在已经准备好程序的所有组件。我们只需要改变我们的计划

show a greeting
do {
    get number from user
    compute the squareroot of that number while logging
    show the user the squareroot
    ask the user if they want to do another computation
} while the user wants the program to keep running
show a farewell

成一个完整的程序:

int main(int argc, char *argv[]) 
{
    //Do this stuff.
}

首先,我们知道如何开始和结束程序。我们想使用我们的函数showGreeting()和来表示问候和告别showFarewell()

int main(int argc, char *argv[]) 
{
    showGreeting();
    //do {
        //get number from user
        //compute the squareroot of that number while logging
        //show the user the squareroot
        //ask the user if they want to do another computation
    //} while the user wants the program to keep running
    showFarewell();
}

我们知道我们想要获取用户输入并至少计算一次平方根,并且我们知道我们可以得到bool表示用户是否想要使用我们的函数计算另一个平方根的a getRunAgain()。我们应该do用户输入和计算while getRunAgain()

int main(int argc, char *argv[]) 
{
    showGreeting();
    do {
        //get number from user
        //compute the squareroot of that number while logging
        //show the user the squareroot
    } while(getRunAgain());
    showFarewell();
}

我们有一个函数getInputNumber(),它返回一个double代表用户想要计算平方根的数字。我们需要使用它double两次,一次作为平方根函数的参数computeSquareRootBabylonian(),一次将输入及其平方根输出给用户。因此,我们需要一个局部变量:

int main(int argc, char *argv[]) 
{
    showGreeting();
    do {
        double number = getInputNumber();
        //compute the squareroot of that number while logging
        //show the user the squareroot
    } while(getRunAgain());
    showFarewell();
}

现在我们的平方根函数computeSquareRootBabylonian()有四个参数:

  • 计算平方根的数量
  • 初始近似
  • 迭代次数
  • 是否记录每个逐次逼近

我们将number作为第一个参数传递。现在,我们可以对剩余的参数进行硬编码1,用于初始近似值、25迭代次数以及true是否记录。

由于我们只需要使用computeSquareRootBabylonian()一次的结果(当注销结果时),我们可以不使用局部变量而逃脱。不过,为了清楚起见,让我们继续使用一个:

int main(int argc, char *argv[]) 
{
    showGreeting();
    do {
        double number = getInputNumber();
        double squareRoot = computeSquareRootBabylonian(number, 1.0f, 25, true);
        //show the user the squareroot
    } while(getRunAgain());
    showFarewell();
}

我们只需要将结果显示给用户:

int main(int argc, char *argv[]) 
{
    showGreeting();
    do {
        double number = getInputNumber();
        double squareRoot = computeSquareRootBabylonian(number, 1.0f, 25, true);
        cout << endl
             << "The square root of " << num << " is " << sqrt << "!" << endl
             << endl;
    } while(getRunAgain());
    showFarewell();
}

该程序遗漏了一件事:配置cout.

int main(int argc, char *argv[]) 
{
    cout.precision(50);
    showGreeting();
    do {
        double number = getInputNumber();
        double squareRoot = computeSquareRootBabylonian(number, 1.0f, 25, true);
        cout << endl
             << "The square root of " << num << " is " << sqrt << "!" << endl
             << endl;
    } while(getRunAgain());
    showFarewell();
}

重述问题

你问了几个问题cout

在这段代码[第一个main函数]中,我专门将小数的精度设置为 15。但是它输出的数字是小数点后 12 位。但在这段代码[第二个main函数]中,它以小数点后 15 位输出。[...] 我很困惑为什么会这样。我试过 cout << fixed << showpoint; 但是当 num 无缘无故输出 15 个零时,它看起来很不愉快。谁能告诉我为什么会发生这种情况以及如何解决它?

为什么我不能超过小数点后 15 位?如果我将精度设置为 30/40,即使在我的计算机计算器中它达到 30/40,它对我的​​输出也没有任何影响。我应该使用另一种整数类型而不是双精度类型吗?

我稍后会解决这些问题。首先,我将描述我自己会如何询问他们,以便在 StackOverflow 上获得更好更快的响应。

要点是发布一个简短的、独立的、正确的(可编译的)示例。那么这里的问题到底是什么?它与使用插入(using operator <<) into std::cout(into std::ostreamin general) 有关。它与double使用std::ostream::precision. 在将问题减少到这一点之后,我将开始查看相关文档,如果没有提供足够的解释,则使用这些关键字在 StackOverflow 上进行搜索。如果我找不到问题的解决方案,我会生成一个示例来说明我遇到的困难。

提出第一个问题

一个问题是,当我们将 cout 的精度设置为 15 时,我们只能得到 12 位小数。让我们编写一个程序,将 a 初始化double为一个值,设置coutto的精度15并将我们的double插入cout

#include <iostream>
using namespace std;

int main(int argc, char *argv[]) 
{
    double value = 1.1111111111111111111111111f;
    cout.precision(15);
    cout << value << endl;
    return 0;
}

这个程序打印出来

1.11111111111111

1这个数字在小数点后只有 14位。虽然这不是我们所希望的(小数点后有 14 位而不是 12 位),但看起来我们走在了正确的轨道上。看起来某种舍入行为正在发生。或许我们应该在小数点后的第 13 位和第 14 位加零:

#include <iostream>
using namespace std;

int main(int argc, char *argv[]) 
{
    double value = 1.1111111111110011111111111f;
    cout.precision(15);
    cout << value << endl;
    return 0;
}

这个程序的输出

1.111111111111

正如我们所希望的那样,只有 12 位数字。所以我们现在有一个简短的、独立的、正确的(可编译的)示例来提出我们的问题。

陈述第一个问题

std::cout用来输出一个double. 我想显示小数点后的前 15 位,或者至少与非零一样多。但是在这段代码中,例如

int main(int argc, char *argv[]) 
{
    double value = 1.1111111111110011111111111f;
    cout.precision(15);
    cout << value << endl;
    return 0;
}

输出1.111111111111不是1.111111111111001我预期的那样。我能够通过使用来解决这个问题std::fixed

int main(int argc, char *argv[]) 
{
    double value = 1.1111111111110011111111111f;
    cout.precision(15);
    cout << std::fixed << value << endl;
    return 0;
}

它确实1.111111111111001按预期输出。不幸的是,即使所有这些数字都为零,使用std::fixed结果总是在小数点后打印 15 位数字。例如来自的输出

int main(int argc, char *argv[]) 
{
    double value = 1.0f;
    cout.precision(15);
    cout << std::fixed << value << endl;
    return 0;
}

1.000000000000000不是1我所希望的。

cout当所有剩余数字为零时,如何使用最多输出 15 个十进制数字和更少?

提出第二个问题

第二个问题是,无论我们设置cout的精度比 15 高多少,我们的输出中只能得到 15 个十进制数字。让我们编写一个程序,将 a 初始化double为一个值,设置coutto的精度30并将我们的double插入cout

int main(int argc, char *argv[]) 
{
    double value = 1.55f;
    cout.precision(30);
    cout << value << endl;
    return 0;
}

这将输出1.5499999523162841796875,一个由小数点后 22 位组成的数字。这表明我们以某种方式不幸地得到了正好 15 位的输出:与我们在提出第一个问题时遇到的相同类型的舍入行为显然是与从平方根函数返回的值的输出进行交互,使得在这种舍入行为下,将打印小数点后十五位数字。


回答问题

您希望插入 a 以double显示cout尽可能多的非零十进制数字,最多 15 个。doubles in的字符串表示cout应至少满足以下测试:

 x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxf ----> "x.xxxxxxxxxxxxxxx"
 x.xxxxx0000000000000000000000000f ----> "x.xxxxx"
 x.000000000000000000000000000000f ----> "x"
 x.00000000000000x000000000000000f ----> "x.00000000000000x"

这不能通过使用任何明显的方式来实现std::ostream::precision。正如您所指出的,我们不能使用std::fixed,因为这肯定会通过我们上面的第三次测试。我们也不能轻易使用默认值,因为如cplusplus.com 所述

在默认的浮点表示法上,精度字段指定要显示的有意义数字的最大数量,包括小数点之前和之后的数字。

这意味着我们需要考虑小数点前的位数。如果小数点前有 3 位,我们需要使用 15+3 的精度,以此类推。

double实现此目的的一种方法是使用 a并返回 a的函数std::string

std::string stringFromDouble(double value, unsigned int decimalDigits)
{
    int integerComponent = abs((value > 0) ? (int)(floor(value)) : (int)(ceil(value)));
    std::ostringstream integerStream;
    integerStream << integerComponent;
    std::string integerString = integerStream.str();
    unsigned int integerLength = integerString.length();

    std::ostringstream stream;
    stream.precision(decimalDigits + integerLength);
    stream << value;
    std::string str = stream.str();
    return str;
}
于 2013-01-13T07:20:55.083 回答