さらに先へ · 23
絶対値・累乗・平方根
符号を取る、何度も掛ける、2乗するとその数になる値を求める。
四則演算の次によく使う三つの計算です。
下の例は二つの点の座標を読み、横と縦に何マス離れているかを表示し、二点の間の距離を小数第2位まで表示し、その距離を超えない最大の整数を表示します。
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)を返すので、整数の変数に入れるには変換が必要です。
2乗はx * xと書けば整数のままで、もっと簡単です。 - 平方根は2乗するとその数になる値です。
sqrtはいつも小数を返します。
45 の平方根は6.708203932499369で、割り切れる 25 も Python と Java では5.0と表示されます。 - 整数の平方根は
r * r <= nとなる最大の整数rです。sqrtの結果の小数を切り捨ててから、掛け直して合わせます。
例のwhileの2行がその確認です。 - 負の数の平方根は数になりません。
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 はコンパイルエラーです |
よくある間違い
sqrt を切り捨てた値を整数の平方根だと信じた
const x = 9007199136250224; // 94906265 * 94906265 - 1
console.log(Math.floor(Math.sqrt(x)));→ 94906265 — しかし 94906265 の2乗は x より 1 大きいです。正しい答えは 94906264 です。大きな数では sqrt の結果が丸められて、ちょうど 94906265 になります。8言語すべてが同じ値を出します
切り捨ててから掛けて確かめます:while (r * r > x) r--; を付けると 94906264 になります。
Python は math.isqrt(x) が正確な答えを返します。
^ で累乗しようとした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))。
Craykon は ^ をコンパイルエラーで知らせてくれます。
小数に整数用の 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 のように2乗どうしを比べれば、小数が入り込みません。平方根が本当に必要なときだけ
sqrt を使い、整数に変換したあとは一度掛けて確かめます。累乗も同じです。
pow は小数で計算するので、とても大きな数では下の桁が狂います。3 を 34 回掛けると
16677181699666569 ですが、Java の (long) Math.pow(3, 34) は 16677181699666568 を返します。Java・C#・C・C++ で大きな整数の累乗が必要なら、
long(long long)の変数に一つずつ掛けていきます。