求一元二次方程

GitHub跳转原题关系图返回列表

用判别式 b²-4ac 的符号三分支:为负输出 No answer!,精度内为零输出重根,否则套求根公式并把两根排序,统一按 %.5f 输出。

OJ: roj

题目 ID: 1058

难度:入门

标签:入门数学浮点数python

创建: 2026-09-29 17:18

更新: 2026-10-04 23:43

题目描述

求一元二次方程 ax2+bx+c=0ax^2+bx+c=0(a≠0a \neq 0)的根,结果精确到小数点后 5 位。输入一行三个浮点数 a,b,ca,b,c;若两根相等输出 x1=x2=...,若两根不等按根小者在前的顺序输出 x1=...;x2=...,若无实根输出 No answer!,数字与符号之间没有空格。 样例输入:-15.97 19.69 12.02;样例输出:x1=-0.44781;x2=1.68075。

思路

先算判别式 Δ=b2−4ac\Delta=b^2-4ac:Δ<−10−12\Delta<-10^{-12} 时输出 No answer!,∣Δ∣<10−12|\Delta|<10^{-12} 时视为重根按 x1=x2= 输出,Δ>10−12\Delta>10^{-12} 时用求根公式算出两根。两根谁大谁小由分母 2a2a 的符号决定,所以算出后要比较交换,保证根小者在前。输出前把 ∣x∣<10−6|x|<10^{-6} 的根写成 00,避免打印出 -0.00000。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-29 17:18
# update_at: 2026-09-29 17:18

import sys
from math import sqrt

DELTA_EPS = 1e-12  # 判别式落在这个范围内视为 0,用于吸收浮点误差
ZERO_EPS = 1e-6    # 根的绝对值小于它时按 0 输出,避免打印出 "-0.00000"


def no_negative_zero(x: float) -> float:
    """把 |x| < 1e-6 的根统一成 0.0:它们本来就显示为 0.00000,顺便去掉 -0.0 的负号。"""
    return 0.0 if abs(x) < ZERO_EPS else x


def solve() -> None:
    a, b, c = map(float, sys.stdin.buffer.read().split())
    delta = b * b - 4 * a * c

    if delta < -DELTA_EPS:  # 判别式显著为负:无实根
        print("No answer!")
        return
    if abs(delta) < DELTA_EPS:  # 判别式在精度内视为 0:两个相等的实根
        print(f"x1=x2={no_negative_zero(-b / (2 * a)):.5f}")
        return

    root = sqrt(delta)  # 与 C++ 的 sqrt 同为正确舍入,避免 1 ulp 级差异
    xs = sorted(((-b + root) / (2 * a), (-b - root) / (2 * a)))  # 根小者在先
    x1, x2 = map(no_negative_zero, xs)                           # 再抹掉负零的符号
    print(f"x1={x1:.5f};x2={x2:.5f}")


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-04 22:30
 * update_at: 2026-10-04 23:43
 */
// roj 1058 求一元二次方程
// 判别式 delta = b^2 - 4ac 的符号决定输出形态,delta > 0 时套求根公式并把两根排序。

#include <cstdio>
#include <cmath>
#include <algorithm>

typedef long long ll;

const double DELTA_EPS = 1e-12; // 判别式落在这个范围内视为 0,用于吸收浮点误差
const double ZERO_EPS = 1e-6;   // 根的绝对值小于它时按 0 输出,避免打印出 "-0.00000"

double a, b, c; // 方程 ax^2 + bx + c = 0 的三个系数

// 把 |x| < 1e-6 的根统一成 0:它们本来就显示为 0.00000,顺便去掉 -0.0 的负号
double no_negative_zero(double x) {
    if (fabs(x) < ZERO_EPS) {
        return 0.0;
    }
    return x;
}

void solve() {
    double delta = b * b - 4 * a * c;

    if (delta < -DELTA_EPS) { // 判别式显著为负:无实根
        printf("No answer!\n");
        return;
    }
    if (fabs(delta) < DELTA_EPS) { // 判别式在精度内视为 0:两个相等的实根
        double x = no_negative_zero(-b / (2 * a));
        printf("x1=x2=%.5f\n", x);
        return;
    }

    double root = sqrt(delta);
    double x1 = (-b + root) / (2 * a);
    double x2 = (-b - root) / (2 * a);
    if (x1 > x2) { // 题面要求根小者在先,直接交换保证顺序
        double t = x1;
        x1 = x2;
        x2 = t;
    }
    x1 = no_negative_zero(x1);
    x2 = no_negative_zero(x2);
    printf("x1=%.5f;x2=%.5f\n", x1, x2);
}

int main() {
    scanf("%lf%lf%lf", &a, &b, &c);
    solve();
    return 0;
}