平方根ボタンのない電卓で、バビロニアの方法(ニュートン法)を使って平方根を求める。 一行目に数の個数 t が与えられ、続く t 行に正の整数 a が一つずつ与えられる。 a ごとに次のように計算する。 最初の見積もり x は a である。 新しい見積もり y = (x + a ÷ x) ÷ 2 を計算し、繰り返し回数を 1 増やす。 割り算はすべて小数部分まで求める実数の割り算で、実数は倍精度(double)である。 y と x の差の絶対値が 0.000000001 より小さいか、繰り返し回数が 100 になったら止める。 そうでなければ x を y に置き換えて、もう一度計算する。 したがって少なくとも一回は計算する。 a ごとに一行で、繰り返し回数と最後の y を空白一つで区切って出力せよ。 y は小数第六位まで四捨五入して出力する。 丸めが境目にかからないように、最後の y に 1000000 を掛けた値の小数部分が 0.499 以上 0.501 以下になる a は与えられない。
入力
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));}