역사적 실수와 이를 해결하는 방법
핵심요약: 대부분의 언어는 윤년 계산에 대한 올바른 동작을 찾지 못합니다.
면책조항: 저는 다양한 프로그래밍 언어에 걸쳐 정확한 통찰력을 제공하기 위해 최선을 다했지만 모든 분야에 전문가가 아닐 수도 있다는 점을 인정합니다. 오류를 발견하거나 의견이 다른 부분이 있는 경우 정중한 댓글을 남겨주시면 즉시 해결해 드리겠습니다.
한 해가 도약인지 아닌지를 결정하는 것은 간단한 수학 문제입니다.
모든 학생은 첫 번째 프로그래밍 과제로 이 문제를 해결할 수 있습니다.
문제를 단순화 하기 위해 100으로 나누어지는 경우를 제외하고 4로 균등하게 나누어지는 해는 윤년이지만 400으로 나누어지는 해는 윤년이라고 가정해 보겠습니다.
실제 세계와 우주 역학은 좀 더 복잡하지만 이는 이 기사의 범위를 벗어납니다.
여러 프로그래밍 언어가 이 문제를 어떻게 해결하는지 살펴보겠습니다.
PHP:
<?php $yearNumber = 2024; $isLeap = date('L', mktime(0, 0, 0, 1, 1, $yearNumber));
SQL(포스트그레SQL):
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
자바스크립트/타입스크립트:
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);
아르 자형:
leap_year(2024)
루비:
year = 2024 is_leap = Date.leap?(year)
빠른:
let yearNumber = 2024 let isLeap = Calendar.current.isDateInLeapYear( Date(timeIntervalSince1970: TimeInterval(yearNumber)))
이러한 언어는 전역 함수를 사용하여 한 해가 도약인지 확인합니다.
이러한 유틸리티 전역 방법은 실수로 책임을 잘못된 위치(전역 액세스 포인트)에 두는 것입니다.
씨#:
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)
비주얼 베이직 .NET:
Dim year As Integer = 2024 Dim isLeap As Boolean = DateTime.IsLeapYear(year)
이러한 언어는 도우미 를 라이브러리로 사용하여 1년이 도약인지 확인합니다.
잘못 배치된 것은 실제 객체에 존재하지 않고 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 객체를 생성하므로 전단 사도 깨질 수 있습니다.
연도는 정수와 다른 프로토콜을 가지며 연도를 정수로 모델링하는 것은 조기 최적화 냄새이자 무엇과 방법을 혼합하는 증상일 수도 있습니다.
연도는 도약인지(정수로는 안 됨) 여부를 알 수 있으며 월( 0 기반 정수, 1 기반 정수 또는 문자열이 아닌 Months )에 대해 알려줄 수 있습니다.
반대로 Integer 의 기능은 곱셈 및 지수화와 같은 산술 연산으로 확장됩니다.
특정 시점을 float , 정수 또는 기타 데이터 유형으로 표현하면 결과가 발생합니다.
현실 세계의 특정 시점을 아주 작은 부분으로 중단할 수 있습니다(그러나 너무 작지 는 않음).
부동 소수점을 사용하는 것은 유효한 옵션이 아닙니다.
0.01 + 0.02 는 0.03이 아니며 이는 부동 소수점을 처리하는 데 끔찍한 결과를 가져옵니다.
우리는 윤년에 대해 이야기 해 왔습니다.
1년이 도약인지 알아야 할 사항은 무엇입니까?
모델링하는 날짜 및 시간 메커니즘은 2024년 2월 28일 후속 날짜를 알아야 합니다.
그러나 이것은 당신의 문제가 아닙니다 .
정보 은닉 원칙에 따라 책임을 비공개 프로토콜로 남겨야 합니다.
은총알은 없습니다.
언어를 현명하게 사용하십시오.
오늘은 2월 29일, 매일 사용하는 도구를 잠시 멈추고 생각해 보는 윤일입니다.
4년 후에 만나요.