{ }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()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

"한 번 계산하고 나서 멈출지 묻는" 반복이라 do-while이 딱 맞아요.
C·C++·Java·C#·JS·TS는 do { … } while (조건);이 있고, 조건은 "계속할" 조건이라 >=로 써요.
Python과 크레이콘에는 do-while이 없어서 while True:/동안 (참)으로 들어가 끝에서 break/그만으로 나와요.
그냥 while로 먼저 물으면 처음에 x와 y가 같아서 한 번도 계산하지 않아요.
나눗셈 함정: Python /, JS·TS·크레이콘 /는 늘 실수 나눗셈이지만, 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>), 크레이콘 수학.절댓값이에요.
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"), 크레이콘 글자.소수자리맞추기(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과 크레이콘 소수자리맞추기는 가장 짧은 표기 "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));}