题目

编写一个 C++ 程序,从标准输入读取圆的半径 r(双精度浮点数),计算圆的周长与面积。分别以默认流输出、保留 2 位小数(定点表示法 std::fixed + std::setprecision(2))以及科学计数法格式输出计算结果,并使用 std::setw 和 std::setfill 实现右对齐表格输出。

输入格式:一行输入一个浮点数,表示圆的半径 r。

输出格式:分行输出默认格式、定点保留 2 位小数、科学计数法以及带宽度填充的整齐格式。若半径小于 0,输出防御错误提示并退出。

数据范围与约定:<code>r ≥ 0.0</code>,双精度浮点数。

思路与算法

1. 流操纵符机制与持久性
<iomanip> 中的操纵符多数具有黏性(Sticky),如 std::fixed 和 std::setprecision(n) 一旦作用于 std::cout,后续所有浮点输出均维持该格式,直到被 std::defaultfloat 复原;而 std::setw(w) 仅单次生效,下一次输出即恢复默认宽度。

2. 浮点输出模型对比
默认模式下,setprecision(n) 表示有效数字总位数(包括整数与小数部分);结合 std::fixed 后,setprecision(n) 严格表示小数点后的精确位数。科学计数法则使用 std::scientific 启用指数形式。

3. 对齐与填充字符
使用 std::left/std::right 配合 std::setw 和 std::setfill('.') 生成点阵报表。注意:setw 只对下一次插入生效,但 setfill 是黏性的,数字列若未改回空格也会用点号补齐;libstdc++ 按字节计宽,UTF-8 中文标签各占 6 字节。

完整程序

#include <iostream>
#include <iomanip>
#include <cmath>

int main() {
    // 提升流 I/O 吞吐性能
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    double r = 0.0;
    if (!(std::cin >> r) || r < 0.0) {
        std::cout << "错误:请输入有效的非负半径数值。\n";
        return 1;
    }

    const double pi = std::acos(-1.0);
    double perimeter = 2.0 * pi * r;
    double area = pi * r * r;

    // 1. 默认流输出
    std::cout << "--- 1. 默认输出 ---\n";
    std::cout << "周长: " << perimeter << ", 面积: " << area << "\n\n";

    // 2. 定点保留 2 位小数
    std::cout << "--- 2. 定点保留2位小数 ---\n";
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "周长: " << perimeter << "\n";
    std::cout << "面积: " << area << "\n\n";

    // 3. 科学计数法保留 4 位小数
    std::cout << "--- 3. 科学计数法 ---\n";
    std::cout << std::scientific << std::setprecision(4);
    std::cout << "周长: " << perimeter << "\n";
    std::cout << "面积: " << area << "\n\n";

    // 4. 重置流状态并格式化对齐打印
    std::cout << std::defaultfloat << std::setprecision(2) << std::fixed;
    std::cout << "--- 4. 宽度对齐表格输出 ---\n";
    std::cout << std::left << std::setw(10) << std::setfill('.') << "半径" 
              << std::right << std::setw(12) << r << "\n";
    std::cout << std::left << std::setw(10) << std::setfill('.') << "周长" 
              << std::right << std::setw(12) << perimeter << "\n";
    std::cout << std::left << std::setw(10) << std::setfill('.') << "面积" 
              << std::right << std::setw(12) << area << "\n";

    return 0;
}

运行示例

输入:

5.5

输出:

--- 1. 默认输出 ---
周长: 34.5575, 面积: 95.0332

--- 2. 定点保留2位小数 ---
周长: 34.56
面积: 95.03

--- 3. 科学计数法 ---
周长: 3.4558e+01
面积: 9.5033e+01

--- 4. 宽度对齐表格输出 ---
半径............5.50
周长...........34.56
面积...........95.03