paint-brush
Artık Yılları Yeniden Düşünmek: Favori Programlama Dilinizin Yaklaşımı Neden Kusurlu Olabilir?by@mcsee
1,043
1,043

Artık Yılları Yeniden Düşünmek: Favori Programlama Dilinizin Yaklaşımı Neden Kusurlu Olabilir?

Çoğu dil artık yıl hesaplaması için doğru davranışı bulamıyor
featured image - Artık Yılları Yeniden Düşünmek: Favori Programlama Dilinizin Yaklaşımı Neden Kusurlu Olabilir?
Maximiliano Contieri HackerNoon profile picture
0-item

Tarihi bir hata ve bunu nasıl çözebilirsiniz?


TL;DR: Çoğu dil artık yıl hesaplaması için doğru davranışı bulamıyor.


Yasal Uyarı: Çeşitli programlama dillerinde doğru bilgiler sağlamak için elimden gelenin en iyisini yapmaya çalışsam da, herkeste uzman olamayabileceğimi kabul ediyorum. Bir hata tespit ederseniz veya herhangi bir noktaya katılmıyorsanız, lütfen saygılı bir yorum bırakın; ben de derhal bu konuyu ele alacağım.

Son teknoloji

Bir yılın sıçrama olup olmadığını (ya da olmadığını) belirlemek basit bir matematik problemidir.

Her öğrenci bunu ilk programlama ödevi olarak çözebilir.

Sorunu basitleştirmek için, bir Yılın, 100'e de bölünebilmesi dışında, 4'e eşit olarak bölünebildiğinde artık yıl olduğunu, ancak 400'e bölünebildiğinde artık yıl olduğunu varsayalım.

Gerçek dünya ve kozmik mekanik biraz daha karmaşıktır ancak bu, bu makalenin kapsamı dışındadır.

Birkaç programlama dilinin bu sorunu nasıl çözdüğünü inceleyelim:

Korkunç Yaklaşım

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;

Bu diller geçerli (veya geçersiz) bir artık gün yaratmaya ve doğruluk değerlerinden yararlanmaya çalışır.

Bu hack, hızlı başarısız ilkesini ihlal ediyor ve milyar dolarlık hatayı kötüye kullanıyor.

Geçersiz bir tarih oluşturmaya çalışmak, ciddi dillerde bir istisna oluşturmalıdır çünkü bu gerçek dünya etki alanında gerçekleşir.

Hataları yüzeyin altına gizlemek gibi başka eylemlerde bulunmak, en az şaşkınlık ilkesini ihlal eder.

Eksik Davranış

Ada:

 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); }

Gitmek:

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

-Haskell:

 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)

- Lua:

 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);

Amaç-C:

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

Güç kalkanı:

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

Pas, paslanma:

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

Küçük konuşma:

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

Yukarıdaki diller yerel destek sağlamamaktadır.

Global işlevleri tanımlamanız veya yardımcıları kullanmanız gerekir.

Yanlış Küresel Yaklaşım

PHP (Yine):

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

R:

 leap_year(2024)

Yakut:

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

Süratli:

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

Bu diller, bir yılın artık olup olmadığını kontrol etmek için genel işlevleri kullanır.

Bu yardımcı küresel yöntemler, sorumluluğu yanlışlıkla yanlış konuma (küresel bir erişim noktasına) yerleştirir.

Yardımcıların Kötü Yaklaşımı

C#:

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

Dart oyunu:

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

Perl:

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

Python:

 import calendar leap = calendar.isleap(2024)

Visual Basic .NET:

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

Bu diller, bir yılın artık bir sıçrama olup olmadığını kontrol etmek için yardımcıları kütüphane olarak kullanır.

Sorumlu bir şekilde yanlış yerleştirilmiş olan, gerçek bir nesnede değil, DateTime ile ilgili işlevlerden oluşan bir çantada mevcuttur.

Yıl Yaklaşımı

Java:

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

Kotlin:

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

Ölçek:

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

Bu diller, bunun bir sıçrama olup olmadığını kontrol etmek için Yıl'a güvenir.

Protokol bijeksiyonda gerçek dünyaya daha yakın

Bu aynı zamanda eşleştirmeyi de bozacağından, Integer nesneleri değil, Year nesneleri oluşturduklarına dikkat edin.

Bir Yılın bir tamsayıdan farklı bir protokolü vardır ve bir Yılı bir tamsayı olarak modellemek aynı zamanda erken bir optimizasyon kokusu ve ne ile nasıl'ın karıştırılmasının bir belirtisi olabilir.

Bir Yıl bunun bir sıçrama olup olmadığını söyleyebilir (bir tamsayı bunu yapmamalıdır) ve size ayları hakkında bilgi verebilir (bunlar 0 tabanlı tam sayılar, 1 tabanlı tam sayılar veya dizeler değil, Months'tur ).

Tam tersine, bir Tamsayı'nın yetenekleri çarpma ve üs alma gibi aritmetik işlemleri de kapsar.

Zaman şaka değil

Zamandaki bir noktayı kayan nokta , tam sayı veya başka herhangi bir veri türü olarak temsil etmenin sonuçları vardır.

Gerçek dünyada zamandaki bir noktayı küçük kesirler halinde kırabilirsiniz (ama çok küçük değil)

Şamandıraların kullanılması geçerli bir seçenek değildir.

0,01 + 0,02, 0,03 değildir ve bunun zaman içindeki kayan nokta noktalarıyla ilgili korkunç sonuçları vardır.

Meydan okuma

Artık yıllardan bahsediyoruz.

Bir yılın bir sıçrama olup olmadığını bilmek için gerekenler nelerdir?

Modelleyeceğiniz tarih ve saat mekaniğinin 28 Şubat 2024 halefini bilmesi gerekiyor.

Ama bu senin sorunun DEĞİL .

Bilgi gizleme ilkesine uygun olarak sorumluluğu özel bir protokole bırakmalısınız.

Çözüm

Gümüş Kurşun yok.

Dilinizi akıllıca kullanın.

Bugün 29 Şubat, durup günlük kullandığınız araçlar üzerinde düşünmek için artık bir gün.

4 yıl sonra görüşürüz.