{ }codelper
do-while ループ小数の割り算絶対値P0130

バビロニアの平方根

平方根ボタンのない電卓で、バビロニアの方法(ニュートン法)を使って平方根を求める。
一行目に数の個数 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 はない
出力
a ごとに一行:繰り返し回数と小数第六位までの y
例 1 · stdin
4
1
2
9
1000000000000
stdout
1 1.000000
5 1.414214
7 3.000000
26 1000000.000000
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

「一回計算してから止めるかを聞く」ループなので 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));}