C++ 標準庫之 iomanip 、操作符 ios::fixed 以及 setprecision 使用的慘痛教訓經驗總結

本菜雞自從退役之後就再也沒怎麼敲過 C++ 代碼,在 C++ 語言下,求解關於浮點數類型的問題時,之前有碰到類似的情況,但是似乎都沒有卡這塊的數據,基本上用一個 setprecision 函數保留幾位有效數字就 AC 了。但這次在計算任意五個數的平均值時卡在了一組數據上,問題如下:

#include <iostream>
#include <iomanip>
#include <stdio.h>
using namespace std;
int main(){
    float a,b,c,d,e;
    cin>>a>>b>>c>>d>>e;
    float ave = (a+b+c+d+e)*1.0/5;
    //cout<<setiosflags(ios::fixed)<<setprecision(2)<<ave*1.0<<endl;
    cout<<setprecision(2)<<ave*1.0<<endl;
    //printf("%.2f",ave);
    return 0;
}
/*
 * Problem: 連續輸入5個數,數的範圍爲0.00~2.00,輸出其平均值,並保留兩位小數。
 *
**/

/*
用例:
1.82 1.86 1.88 1.65 1.78

對應輸出應該爲:

1.80

你的輸出爲:

1.8

*
**/

我們從頭到尾來看看這段代碼吧。

首先是頭文件:#include ,我們可能沒太見過,老實說我也是第一次見,以前都是用 C++ 那個總的頭文件 #include<bits/stdc++.h> ,包含了全部的C++頭文件,所以很多小的頭文件可能都不太記得。

關於 bits/stdc++.h 的源代碼如下:

// C++ includes used for precompiling -*- C++ -*-

// Copyright (C) 2003-2014 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file stdc++.h
 *  This is an implementation file for a precompiled header.
 */

// 17.4.1.2 Headers

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif

include 是 I/O 流控制頭文件,類似與 C 裏面的格式化輸出一樣,記住就好,具體的一些操作符及作用可以參考下表所示。

操作符 作用
dec 設置整數爲十進制
hex 設置整數爲十六進制
oct 設置整數爲八進制
setbase(n) 設置整數爲n進制(n=8,10,16)
setfill(n) 設置字符填充,c可以是字符常或字符變量
setprecision(n) 設置浮點數的有效數字爲n位
setw(n) 設置字段寬度爲n位
setiosflags(ios::fixed) 設置浮點數以固定的小數位數顯示
setiosflags(ios::scientific) 設置浮點數以科學計數法表示
setiosflags(ios::left) 輸出左對齊
setiosflags(ios::right) 輸出右對齊
setiosflags(ios::skipws) 忽略前導空格
setiosflags(ios::uppercase) 在以科學計數法輸出E與十六進制輸出X以大寫輸出,否則小寫
setiosflags(ios::showpos) 輸出正數時顯示"+"號
setiosflags(ios::showpoint) 強制顯示小數點
resetiosflags() 終止已經設置的輸出格式狀態,在括號中應指定內容

浮點數但是我們要記住的一點是,一個浮點數的有效數字位數默認爲爲 6 位,你可以通過 setprecision(n) 操作符來修改顯示有效數字的有效數字的位數。但我們需要注意以下兩個重要的易錯點:

  • 如果有效數少於要顯示的數字,則 setprecision 將捨去
  • 末尾的零將被省略

那我們如果想要根據我們自己的意願輸出小數點後相應的位數,我們又該怎麼辦呢?

C++ 在 iostream 頭文件中定義了一個 ios::fixed 操作符,它可以使輸出數據用小數點的形式打印在屏幕上。這樣我們就可以人爲的控制輸出自己想保留小數點後相應的位數。

setiosflags(ios::fixed) 是定義在 中的函數,該操作符的作用是執行有參數指定區域內的動作,我們傳入了參數 ios::fixed ,該參數指定的動作是以帶小數點的形式表示浮點數,並且在允許的精度範圍內儘可能的把數字移向小數點右側。

例如我們還是拿上面那個例子來說:

cout<<ave*1.0<<endl;                                                (1)
cout<<setprecision(2)<<ave*1.0<<endl;                               (2)
cout<<setiosflags(ios::fixed)<<ave*1.0<<endl;                       (3)
cout<<setiosflags(ios::fixed)<<setprecision(2)<<ave*1.0<<endl;      (4)

根據上面所描述的那樣,我們很容易得出如下結果:

(1) = 1.798
(2) = 1.8
(3) = 1.798000
(4) = 1.80
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章