在没有平方根按钮的计算器上,用巴比伦方法(牛顿法)求平方根。 第一行给出个数 t,接下来 t 行每行给出一个正整数 a。 对每个 a 按如下方式计算。 初始估计值 x 是 a。 计算新的估计值 y = (x + a ÷ x) ÷ 2,并把迭代次数加 1。 所有除法都是保留小数部分的浮点除法,浮点数是双精度(double)。 如果 y 与 x 之差的绝对值小于 0.000000001,或迭代次数达到 100,就停止。 否则把 x 换成 y,再计算一次。 所以至少会计算一次。 对每个 a 在一行中输出迭代次数和最后的 y,用一个空格隔开。 y 四舍五入到小数点后第六位输出。 为了不让四舍五入落在分界上,不会给出这样的 a:最后的 y 乘以 1000000 后的小数部分在 0.499 到 0.501 之间(含两端)。
输入
1 ≤ t ≤ 100,1 ≤ a ≤ 10^12,不会有使 y × 10^6 的小数部分在 0.499~0.501 之间的 a
这是“先算一次再问要不要停”的循环,正适合 do-while。 C、C++、Java、C#、JS、TS 有 do { … } while (条件);,条件是“继续”的条件,所以写 >=。 Python 和 Craykon 没有 do-while,用 while True:/当 (真) 进入,在末尾用 break/跳出 离开。 用普通的 while 先判断的话,一开始 x 和 y 相等,一次也不会计算。 除法陷阱:Python / 以及 JS、TS、Craykon 的 / 总是浮点除法,但 Python // 是整数商。 在 Java、C#、C、C++ 中,a / x 至少一边是 double 才是浮点除法,所以要让 x 是 double(两边都是整数就只剩商)。 绝对值陷阱:估计值从上方逼近,所以 y - x 是负数。 不取绝对值而写 y - x < 1e-9,第一轮就会停。 浮点数绝对值:Python abs,JS/TS Math.abs,Java Math.abs,C# Math.Abs,C++ std::abs(<cmath>),Craykon 数学.绝对值。 C 的 abs 用于 int(<stdlib.h>),浮点差 0.5 会变成 0 而过早停止。 C 中要用 fabs(<math.h>)。 保留六位小数输出:Python f"{y:.6f}",JS/TS y.toFixed(6),C/C++ printf("%.6f"),Craykon 字符.保留小数(y, 6)。 Java String.format("%.6f") 和 C# ToString("F6") 会按计算机的区域设置可能输出逗号,所以要传入 Locale.ROOT、CultureInfo.InvariantCulture。 a 不超过 10^12 时,最后两个估计值之差是 double 的一格(约 10^-10),一定会停;但 a 大得多时这一格大于 10^-9,循环可能永远停不下来。 次数上限 100 就是这道保险。 排除四舍五入分界的原因:√999999999999 = 999999.99999949999…,对这个 double,C、C++、Python、JS、C# 按精确值舍入得到 999999.999999,而 Java String.format 和 Craykon 字符.保留小数 对最短表示 "999999.9999995" 舍入,输出 1000000.000000。
Pythonmain.py · 13 行
t = int(input())for _ in range(t): a = int(input()) x = float(a) count = 0 # 파이썬에는 do-while이 없다: while True로 들어가서 끝에서 멈출지 묻는다 while True: y = (x + a / x) / 2 # /는 늘 실수 나눗셈 count += 1 if abs(y - x) < 1e-9 or count == 100: break x = y print(count, f"{y:.6f}")
JavaScriptmain.js · 16 行
const [t, ...nums] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const out = [];for (let i = 0; i < t; i++) { const a = nums[i]; let x = a; let y = a; let count = 0; // 한 번은 꼭 계산한 뒤 멈출지 묻는다 do { x = y; y = (x + a / x) / 2; count++; } while (Math.abs(y - x) >= 1e-9 && count < 100); out.push(count + " " + y.toFixed(6));}console.log(out.join("\n"));
TypeScriptmain.ts · 17 行
import { readFileSync } from "node:fs";const [t, ...nums]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);const out: string[] = [];for (let i = 0; i < t; i++) { const a: number = nums[i]; let x: number = a; let y: number = a; let count = 0; // 한 번은 꼭 계산한 뒤 멈출지 묻는다 do { x = y; y = (x + a / x) / 2; count++; } while (Math.abs(y - x) >= 1e-9 && count < 100); out.push(count + " " + y.toFixed(6));}console.log(out.join("\n"));
JavaMain.java · 24 行
import java.util.Locale;import java.util.Scanner;public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int t = sc.nextInt(); StringBuilder out = new StringBuilder(); for (int i = 0; i < t; i++) { long a = sc.nextLong(); double x; double y = a; int count = 0; // 한 번은 꼭 계산한 뒤 멈출지 묻는다 do { x = y; y = (x + a / x) / 2; // x가 double이라 a / x도 실수 나눗셈 count++; } while (Math.abs(y - x) >= 1e-9 && count < 100); out.append(count).append(' ').append(String.format(Locale.ROOT, "%.6f", y)).append('\n'); } System.out.print(out); }}
C#Main.cs · 28 行
using System;using System.Globalization;using System.Text;class Program{ static void Main() { int t = int.Parse(Console.ReadLine()); var sb = new StringBuilder(); for (int i = 0; i < t; i++) { long a = long.Parse(Console.ReadLine()); double x; double y = a; int count = 0; // 한 번은 꼭 계산한 뒤 멈출지 묻는다 do { x = y; y = (x + a / x) / 2; // x가 double이라 a / x도 실수 나눗셈 count++; } while (Math.Abs(y - x) >= 1e-9 && count < 100); sb.Append(count).Append(' ').Append(y.ToString("F6", CultureInfo.InvariantCulture)).Append('\n'); } Console.Write(sb); }}
C++main.cpp · 22 行
#include <cmath>#include <cstdio>#include <iostream>int main() { int t; std::cin >> t; for (int i = 0; i < t; i++) { long long a; std::cin >> a; double x; double y = static_cast<double>(a); int count = 0; // 한 번은 꼭 계산한 뒤 멈출지 묻는다 do { x = y; y = (x + a / x) / 2; // x가 double이라 a / x도 실수 나눗셈 count++; } while (std::abs(y - x) >= 1e-9 && count < 100); std::printf("%d %.6f\n", count, y); }}
Cmain.c · 22 行
#include <math.h>#include <stdio.h>int main(void) { int t; scanf("%d", &t); for (int i = 0; i < t; i++) { long long a; scanf("%lld", &a); double x; double y = (double)a; int count = 0; // 한 번은 꼭 계산한 뒤 멈출지 묻는다 do { x = y; y = (x + a / x) / 2; // x가 double이라 a / x도 실수 나눗셈 count++; } while (fabs(y - x) >= 1e-9 && count < 100); // 실수 절댓값은 fabs printf("%d %.6f\n", count, y); } return 0;}
Craykonmain.cray · 20 行
t = 控制台.读行().转数字();循环 (i = 0; i < t; i++){ a = 控制台.读行().转数字(); x = a; y = a; count = 0; // 크레이콘에는 do-while이 없다: 동안 (참)으로 들어가서 끝에서 멈출지 묻는다 当 (真) { y = (x + a / x) / 2; // /는 늘 실수 나눗셈 count += 1; 如果 (数学.绝对值(y - x) < 1e-9 || count == 100) { 跳出; } x = y; } 控制台.输出(count + " " + 字符.保留小数(y, 6));}