Problem 893: Y3K Problem

Pemecahan soal ini tergolong mudah, yaitu copy + paste dari unit SysUtils di Delphi. Sebenarnya tidak sulit untuk mengerjakan sendiri, tetapi godaan untuk tidak mencontek sangat besar, dan saya memilih menyerah dengan godaan itu. Penyesuaian tetap perlu diadakan, mengingat TDateTime di Delphi adalah bertipe Double sedangkan Integer sudah mencukupi. Termasuk pula pengecekan apakah cakupan hari, bulan dan tahun tidak melewati batas, yang bisa ditiadakan di soal ini.

Hikmah menarik dari soal ini ternyata FreePascal dalam kondisi default menyatakan Integer sebagai Smallint (16 bit). Jamaknya dalam program-program Windows saat ini Integer adalah 32 bit. Awalnya hal ini cukup memusingkan mengingat program berjalan baik di Delphi tetapi kacau hasilnya di FreePascal. Masalah terselesaikan dengan menambahkan directive ‘$MODE Delphi’. Tak lupa pula tambahan directive ‘$OPTIMIZATION ON’ yang mempercepat sekitar 0,010 detik.

Versi asli dari SysUtils menggunakan procedure DivMod untuk melakukan operasi pembagian (Div) dan sisa pembagian (Mod) dalam sekali genjot. Processor Intel ketika melakukan operasi pembagian (DIV) menyimpan hasil pembagian pada register (E)AX dan sisa pembagian pada register (E)DX. Namun mengingat ini sangat bergantung mesin maka bisa diabaikan saja, yaitu dengan melakukan operasi Div dan Mod secara terpisah.

Soal: UVa Online Judge: 893 – Y3K Problem


program y3k_893;

{$APPTYPE CONSOLE}
{$IFNDEF VER150}
{$MODE Delphi}
{$OPTIMIZATION ON}
{$ENDIF}

type
  PDayTable = ^TDayTable;
  TDayTable = array[1..12] of Word;

const
  _MonthDays: array [Boolean] of TDayTable =
  ((31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
  (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31));

function _IsLeapYear(Year: Word): Boolean;
begin
  _IsLeapYear := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0));
end;

function _EncodeDate(Year, Month, Day: Word): Integer;
var
  I: Integer;
  DayTable: PDayTable;
begin
  DayTable := @_MonthDays[_IsLeapYear(Year)];
  for I := 1 to Month – 1 do Inc(Day, DayTable^[I]);
  I := Year – 1;
  Result := I * 365 + I div 4 – I div 100 + I div 400 + Day;
end;

procedure _DecodeDate(TD: Integer);
const
  D1 = 365;
  D4 = D1 * 4 + 1;
  D100 = D4 * 25 – 1;
  D400 = D100 * 4 + 1;
var
  Y, M, D, I: Integer;
  DayTable: PDayTable;
begin
  Dec(TD);
  Y := 1;

  Inc(Y, (TD div D400) * 400);
  TD := TD mod D400;

  I := TD div D100;
  D := TD mod D100;
  if I = 4 then begin
    Dec(I);
    Inc(D, D100);
  end;
  Inc(Y, I * 100);

  I := D div D4;
  D := D mod D4;
  Inc(Y, I * 4);

  I := D div D1;
  D := D mod D1;
  if I = 4 then begin
    Dec(I);
    Inc(D, D1);
  end;

  Inc(Y, I);
  DayTable := @_MonthDays[_IsLeapYear(Y)];

  M := 1;
  while True do begin
    I := DayTable^[M];
    if D < I then Break;
    Dec(D, I);
    Inc(M);
  end;
  Writeln(D + 1, ‘ ‘, M, ‘ ‘, Y);
end;

var
  Hari: Integer;
  Tg, Bl, Th: Word;
  {$IFDEF VER150}FT: Text;{$ENDIF}
begin
  {$IFDEF VER150}
  Assign(FT, ‘y3k.txt’);
  Reset(FT);
  {$ENDIF}
  Readln({$IFDEF VER150}FT,{$ENDIF} Hari, Tg, Bl, Th);
  while Tg > 0 do begin
    _DecodeDate(_EncodeDate(Th, Bl, Tg) + Hari);
    Readln({$IFDEF VER150}FT,{$ENDIF} Hari, Tg, Bl, Th);
  end;
  {$IFDEF VER150}Readln;{$ENDIF}
end.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s