더 나아가기 · 23
절댓값·거듭제곱·제곱근
부호 떼기, 여러 번 곱하기, 제곱해서 그 수가 되는 값 찾기.
사칙연산 다음으로 자주 쓰는 계산 세 가지예요.
아래 예제는 두 점의 좌표를 읽어서 가로와 세로로 떨어진 칸 수를 찍고, 두 점 사이의 거리를 소수 둘째 자리까지 찍고, 그 거리를 넘지 않는 가장 큰 정수를 찍어요.
import math x1, y1, x2, y2 = map(int, input().split()) dx = abs(x2 - x1) # 3dy = abs(y2 - y1) # 1 - 7 = -6 → 6print(dx, dy) d2 = dx ** 2 + dy ** 2 # 45, 정수끼리라 정수 그대로dist = math.sqrt(d2) # 6.708203932499369print(f"{dist:.2f}") # 정수 제곱근: r * r <= d2인 가장 큰 정수r = int(dist)while r * r > d2: r -= 1while (r + 1) * (r + 1) <= d2: r += 1print(r) # math.isqrt(d2)도 같은 답const [x1, y1, x2, y2] = require("fs").readFileSync(0, "utf8").trim().split(" ").map(Number); const dx = Math.abs(x2 - x1); // 3const dy = Math.abs(y2 - y1); // 1 - 7 = -6 → 6console.log(dx, dy); const d2 = dx ** 2 + dy ** 2; // 45const dist = Math.sqrt(d2); // 6.708203932499369console.log(dist.toFixed(2)); // 정수 제곱근: r * r <= d2인 가장 큰 정수let r = Math.floor(dist);while (r * r > d2) r--;while ((r + 1) * (r + 1) <= d2) r++;console.log(r);import { readFileSync } from "node:fs";const [x1, y1, x2, y2]: number[] = readFileSync(0, "utf8").trim().split(" ").map(Number); const dx: number = Math.abs(x2 - x1); // 3const dy: number = Math.abs(y2 - y1); // 1 - 7 = -6 → 6console.log(dx, dy); const d2: number = dx ** 2 + dy ** 2; // 45const dist: number = Math.sqrt(d2); // 6.708203932499369console.log(dist.toFixed(2)); // 정수 제곱근: r * r <= d2인 가장 큰 정수let r: number = Math.floor(dist);while (r * r > d2) r--;while ((r + 1) * (r + 1) <= d2) r++;console.log(r);import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int x1 = in.nextInt(), y1 = in.nextInt(), x2 = in.nextInt(), y2 = in.nextInt(); int dx = Math.abs(x2 - x1); // 3 int dy = Math.abs(y2 - y1); // 1 - 7 = -6 → 6 System.out.println(dx + " " + dy); int d2 = (int) (Math.pow(dx, 2) + Math.pow(dy, 2)); // pow는 double을 돌려줘요 double dist = Math.sqrt(d2); // 6.708203932499369 System.out.println(String.format("%.2f", dist)); // 정수 제곱근: r * r <= d2인 가장 큰 정수 int r = (int) dist; while (r * r > d2) r--; while ((r + 1) * (r + 1) <= d2) r++; System.out.println(r); }}using System; class Program{ static void Main() { string[] p = Console.ReadLine().Split(' '); int x1 = int.Parse(p[0]), y1 = int.Parse(p[1]), x2 = int.Parse(p[2]), y2 = int.Parse(p[3]); int dx = Math.Abs(x2 - x1); // 3 int dy = Math.Abs(y2 - y1); // 1 - 7 = -6 → 6 Console.WriteLine($"{dx} {dy}"); int d2 = (int)(Math.Pow(dx, 2) + Math.Pow(dy, 2)); // Pow는 double을 돌려줘요 double dist = Math.Sqrt(d2); // 6.708203932499369 Console.WriteLine(dist.ToString("F2")); // 정수 제곱근: r * r <= d2인 가장 큰 정수 int r = (int)dist; while (r * r > d2) r--; while ((r + 1) * (r + 1) <= d2) r++; Console.WriteLine(r); }}#include <cmath>#include <iomanip>#include <iostream> int main() { int x1, y1, x2, y2; std::cin >> x1 >> y1 >> x2 >> y2; int dx = std::abs(x2 - x1); // 3 int dy = std::abs(y2 - y1); // 1 - 7 = -6 → 6 std::cout << dx << ' ' << dy << '\n'; int d2 = (int)(std::pow(dx, 2) + std::pow(dy, 2)); // pow는 double을 돌려줘요 double dist = std::sqrt(d2); // 6.708203932499369 std::cout << std::fixed << std::setprecision(2) << dist << '\n'; // 정수 제곱근: r * r <= d2인 가장 큰 정수 int r = (int)dist; while (r * r > d2) r--; while ((r + 1) * (r + 1) <= d2) r++; std::cout << r << '\n';}#include <stdio.h>#include <stdlib.h>#include <math.h> int main(void) { int x1, y1, x2, y2; scanf("%d %d %d %d", &x1, &y1, &x2, &y2); int dx = abs(x2 - x1); /* 3 — abs는 정수용, 실수는 fabs */ int dy = abs(y2 - y1); /* 1 - 7 = -6 → 6 */ printf("%d %d\n", dx, dy); int d2 = (int)(pow(dx, 2) + pow(dy, 2)); /* pow는 double을 돌려줘요 */ double dist = sqrt(d2); /* 6.708203932499369 */ printf("%.2f\n", dist); /* 정수 제곱근: r * r <= d2인 가장 큰 정수 */ int r = (int)dist; while (r * r > d2) r--; while ((r + 1) * (r + 1) <= d2) r++; printf("%d\n", r); return 0;}p = 콘솔.수들읽기();x1 = p[0];y1 = p[1];x2 = p[2];y2 = p[3]; dx = 수학.절댓값(x2 - x1); // 3dy = 수학.절댓값(y2 - y1); // 1 - 7 = -6 → 6콘솔.쓰기(dx + " " + dy); d2 = dx * dx + dy * dy; // 거듭제곱 함수가 없어서 곱해요dist = 수학.제곱근(d2); // 6.708203932콘솔.쓰기(글자.소수자리맞추기(dist, 2)); // 정수 제곱근: r * r <= d2인 가장 큰 정수r = 수학.내림(dist);동안 (r * r > d2){ r--;}동안 ((r + 1) * (r + 1) <= d2){ r++;}콘솔.쓰기(r);2 7 5 1
3 6 6.71 6
핵심
- 절댓값은 부호를 뗀 크기예요.
두 값이 얼마나 떨어져 있는지 구할 때 써요.
어느 쪽이 큰지 몰라도abs(a - b)면 돼요.1 - 7은 -6이지만 떨어진 칸 수는 6이에요. - 거듭제곱은 같은 수를 여러 번 곱하는 계산이에요.
Python과 JavaScript에는**연산자가 있고, 나머지 언어는pow함수를 써요.^는 어느 언어에서도 거듭제곱이 아니에요. - 거듭제곱의 결과가 정수인지 실수인지는 언어마다 달라요.
Python의2 ** 10은 정수1024예요.
Java·C#·C·C++의pow는 정수를 넣어도 실수(double)를 돌려줘서, 정수 변수에 담으려면 바꿔 줘야 해요.
제곱은x * x로 쓰면 정수 그대로라 더 간단해요. - 제곱근은 제곱하면 그 수가 되는 값이에요.
sqrt는 늘 실수를 돌려줘요.
45의 제곱근은6.708203932499369이고, 딱 떨어지는 25도 Python과 Java에서는5.0으로 찍혀요. - 정수 제곱근은
r * r <= n인 가장 큰 정수r이에요.sqrt의 결과에서 소수를 버린 다음, 다시 곱해 보고 맞춰요.
예제의while두 줄이 그 확인이에요. - 음수의 제곱근은 수로 나오지 않아요.
Python은ValueError로 멈추고, 나머지 언어는NaN(수가 아님)을 돌려주고 그대로 진행해요.
언어별로 쓰는 법
| Python | abs(x), x ** 2, math.sqrt(x)(import math).정수 제곱근은 math.isqrt(n)이 바로 구해 줘요.2 64도 정확한 정수이고, 2 -1은 0.5예요.-2 2는 -4라서 (-2) 2로 써요 |
|---|---|
| JavaScript | Math.abs(x), x ** 2(또는 Math.pow(x, 2)), Math.sqrt(x), 버림은 Math.floor(...).-2 2는 SyntaxError라서 (-2) 2로 써요 |
| TypeScript | JavaScript와 같아요. 결과는 모두 number예요 |
| Java | Math.abs(x), Math.pow(x, 2), Math.sqrt(x).Math.pow(2, 10)은 1024.0이에요.int p = Math.pow(2, 10);은 컴파일 오류라서 (int) Math.pow(2, 10)으로 바꿔요 |
| C# | Math.Abs(x), Math.Pow(x, 2), Math.Sqrt(x).Math.Pow는 double이라 int p = Math.Pow(2, 10);은 오류 CS0266이에요.(int)Math.Pow(2, 10)으로 바꿔요 |
| C++ | <cmath>의 std::abs(x), std::pow(x, 2), std::sqrt(x).std::pow는 double이라 std::cout << std::pow(10, 6)은 1e+06으로 찍혀요.정수로 찍으려면 (long long)으로 바꿔요 |
| C | 정수 절댓값은 <stdlib.h>의 abs(x), 실수 절댓값은 <math.h>의 fabs(x).pow(x, 2)와 sqrt(x)도 <math.h>에 있고 double을 돌려줘요 |
| Craykon | 수학.절댓값(x), 수학.제곱근(x), 버림은 수학.내림(...).거듭제곱은 연산자도 함수도 없어서 x * x처럼 곱해요.2 ^ 10과 2 ** 10은 컴파일 오류예요 |
자주 하는 실수
^로 거듭제곱을 하려고 했어요Python · JavaScript · TypeScript · Java · C# · C · C++
System.out.println(2 ^ 10);→ 8 — 1024가 아니에요. ^는 두 수의 비트를 견주는 다른 연산(XOR)이에요. 오류 없이 엉뚱한 수가 나와요
Python과 JavaScript는 2 ** 10, 나머지는 pow 함수를 써요(Java는 (int) Math.pow(2, 10)).
크레이콘은 ^를 컴파일 오류로 알려 줘요.
sqrt를 버림한 값을 정수 제곱근으로 믿었어요
const x = 9007199136250224; // 94906265 * 94906265 - 1
console.log(Math.floor(Math.sqrt(x)));→ 94906265 — 그런데 94906265의 제곱은 x보다 1 커요. 맞는 답은 94906264예요. 큰 수에서는 sqrt의 결과가 반올림되어 딱 94906265가 돼요. 8개 언어 모두 같은 값을 내요
버림한 다음 곱해서 확인해요: while (r * r > x) r--;를 붙이면 94906264가 돼요.
Python은 math.isqrt(x)가 정확한 답을 줘요.
실수에 정수용 abs를 썼어요C · C++
double d = -2.7;
printf("%d\n", abs(d));→ 2 — 2.7이 아니에요. <stdlib.h>의 abs는 정수용이라서 소수 부분이 먼저 버려져요. C++에서도 std:: 없이 abs(d)라고 쓰면 2가 나왔어요
C는 fabs(d), C++는 std::abs(d)를 써요.
둘 다 2.7이에요.
언어마다 다른 점
답이 정수여야 하는 문제에서는 되도록 정수 안에서 계산해요.
거리가
제곱근이 꼭 필요할 때만
거듭제곱도 마찬가지예요.
3을 34번 곱하면
Java·C#·C·C++에서 큰 정수 거듭제곱이 필요하면
답이 정수여야 하는 문제에서는 되도록 정수 안에서 계산해요.
거리가
r 이하인지 물을 때는 sqrt를 쓰지 않고 dx * dx + dy * dy <= r * r처럼 제곱끼리 견주면 실수가 끼어들지 않아요.제곱근이 꼭 필요할 때만
sqrt를 쓰고, 정수로 바꾼 뒤에는 한 번 곱해서 확인해요.거듭제곱도 마찬가지예요.
pow는 실수로 계산해서 아주 큰 수에서는 끝자리가 틀려요.3을 34번 곱하면
16677181699666569인데 Java의 (long) Math.pow(3, 34)는 16677181699666568을 줘요.Java·C#·C·C++에서 큰 정수 거듭제곱이 필요하면
long(long long) 변수에 하나씩 곱해요.