paint-brush
うるう年を再考する: お気に入りのプログラミング言語のアプローチに欠陥がある理由@mcsee
1,059 測定値
1,059 測定値

うるう年を再考する: お気に入りのプログラミング言語のアプローチに欠陥がある理由

Maximiliano Contieri5m2024/02/29
Read on Terminal Reader

長すぎる; 読むには

ほとんどの言語は、うるう年の計算の正しい動作を見つけることができません。
featured image - うるう年を再考する: お気に入りのプログラミング言語のアプローチに欠陥がある理由
Maximiliano Contieri HackerNoon profile picture
0-item

歴史的な間違いとその解決方法


TL;DR: ほとんどの言語は、うるう年の計算の正しい動作を見つけることができません。


免責事項: 私はさまざまなプログラミング言語について正確な洞察を提供するために最善を尽くしてきましたが、すべての言語の専門家ではない可能性があることを認めます。間違いを見つけたり、同意できない点がある場合は、敬意を持ってコメントを残してください。すぐに対処します。

技術水準

ある年がうるう年であるかどうかを判断するのは、単純な数学的問題です。

すべての生徒が最初のプログラミング課題として解くことができます。

問題を単純化するために、年が 4 で割り切れる場合は閏年とします。ただし、100 で割り切れる場合は除きますが、400 で割り切れる場合は閏年とします。

現実世界と宇宙の力学はもう少し複雑ですが、それはこの記事の範囲を超えています。

いくつかのプログラミング言語がこの問題をどのように解決するかを見てみましょう。

恐ろしいアプローチ

PHP:

 <?php $yearNumber = 2024; $isLeap = date('L', mktime(0, 0, 0, 1, 1, $yearNumber));

SQL (PostgreSQL):

 SELECT (EXTRACT(year FROM TIMESTAMP '2024-02-29') IS NOT NULL) AS is_leap_year;

これらの言語は、有効な (または無効な) うるう日を作成し、真実の値を利用しようとします。

このハッキングはフェイルファストの原則に違反し、数十億ドルの間違いを悪用します。

無効な日付を作成しようとすると、現実世界のドメインで発生するため、本格的な言語では例外がスローされるはずです。

間違いを水面下に隠すなど、他の行為を行うと、驚きを最小化する原則に違反します。

欠落している動作

エイダ:

 function Is_Leap_Year (Year : Integer) return Boolean is begin return (Year mod 4 = 0 and then Year mod 100 /= 0) or else (Year mod 400 = 0); end Is_Leap_Year;

C/C++:

 bool isLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); }

行く:

 package main import ( "fmt" "time" ) func isLeapYear(year int) bool { return year%4 == 0 && (year%100 != 0 || year%400 == 0) }

ハスケル:

 import Data.Time.Calendar (isLeapYear) let year = 2024 let isLeap = isLeapYear year

JavaScript/TypeScript:

 function isLeapYear(year) { return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0); }

ジュリア:

 using Dates year = 2024 isleap(year)

ルア:

 local year = 2024 local isLeap = (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0)

MATLAB:

 year = 2024; isLeap = mod(year, 4) == 0 && (mod(year, 100) ~= 0 || mod(year, 400) == 0);

目標-C:

 int yearNumber = 2024; BOOL isLeap = (yearNumber % 4 == 0 && yearNumber % 100 != 0) || (yearNumber % 400 == 0);

パワーシェル:

 $yearNumber = 2024 $isLeap = ($yearNumber % 4 -eq 0 -and $yearNumber % 100 -ne 0) -or ($yearNumber % 400 -eq 0)

さび:

 fn is_leap_year(year: i32) -> bool { (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) }

雑談:

 | yearNumber | yearNumber := 2024. (yearNumber \\ 4 = 0) and: [(yearNumber \\ 100 ~= 0) or: [ yearNumber \\ 400 = 0 ]]

上記の言語はネイティブ サポートを提供しません。

グローバル関数を定義するか、ヘルパーを使用する必要があります。

間違ったグローバルアプローチ

PHP (もう一度):

 <?php $yearNumber = 2024; $isLeap = checkdate(2, 29, $yearNumber);

R:

 leap_year(2024)

ルビィ:

 year = 2024 is_leap = Date.leap?(year)

迅速:

 let yearNumber = 2024 let isLeap = Calendar.current.isDateInLeapYear( Date(timeIntervalSince1970: TimeInterval(yearNumber)))

これらの言語は、グローバル関数を使用して、年がうるうかどうかを確認します。

これらのユーティリティグローバル メソッドは、誤って責任を間違った場所 (グローバル アクセス ポイント) に置きます。

ヘルパーの悪いアプローチ

C#:

 int yearNumber = 2024; bool isLeap = System.DateTime.IsLeapYear(yearNumber);

ダーツ:

 import 'package:intl/intl.dart'; var year = 2024; var isLeap = DateTime(year).isLeapYear;

パール:

 use Time::Piece; my $yearNumber = 2024; my $isLeap = Time::Piece ->strptime("$yearNumber-01-01", "%Y-%m-%d")->leapyear;

パイソン:

 import calendar leap = calendar.isleap(2024)

Visual Basic .NET:

 Dim year As Integer = 2024 Dim isLeap As Boolean = DateTime.IsLeapYear(year)

これらの言語は、年がうるうかどうかをチェックするためのライブラリとしてヘルパーを使用します。

間違って配置されたものは、実際のオブジェクトには存在せず、 DateTime 関連の関数の中に存在します。

年の近づき

ジャバ:

 int yearNumber = 2024; boolean isLeap = java.time.Year.of(yearNumber).isLeap();

コトリン:

 val yearNumber = 2024 val isLeap = java.time.Year.of(yearNumber).isLeap

スカラ:

 val year = 2024 val isLeap = java.time.Year.of(year).isLeap

これらの言語は、に基づいて閏かどうかを確認します。

全単射ではプロトコルがより現実世界に近くなります

これにより全単射も壊れてしまうため、 IntegerオブジェクトではなくYearオブジェクトが作成されることに注意してください。

Yearには整数とは異なるプロトコルがあり、 Year を整数としてモデル化することは、時期尚早な最適化の匂いであり、 what と howが混在している兆候となります。

Year は、それが閏であるかどうかを知ることができ (整数では閏を行うべきではありません)、そのについても知ることができます (これは、 0 から始まる整数、1 から始まる整数、または文字列ではなく、 Months です)。

逆に、 Integerの機能は乗算や累乗などの算術演算に拡張されます。

時間は冗談じゃない

ある時点をfloatinteger 、またはその他のデータ型で表すと、結果が生じます。

現実世界では、ある時点をほんの少しずつ区切ることができます (ただし、 小さすぎることはありません)。

floatの使用は有効なオプションではありません。

0.01 + 0.02 は0.03 ではありません。これは、浮動小数点時点の処理に恐ろしい結果をもたらします。

チャレンジ

うるう年の話をしてきました。

その年が閏年であるかどうかを知る必要があるのは何ですか?

モデル化する日付と時刻のメカニズムでは、2024 年 2 月 28 日の後継を知る必要があります。

しかし、これはあなたの問題ではありません

情報隠蔽の原則に従い、プライベート プロトコルとして責任を負う必要があります。

結論

特効薬はありません。

言語を賢く使用してください。

今日 2 月 29 日は、毎日使用しているツールについて立ち止まって振り返るための閏日です。

4年後にお会いしましょう。