Problem 893: Y3K Problem

March 15, 2009 at 1:40 am | Posted in General | 1 Comment
Tags: ,

Oleh: Mpu Gondrong

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.

http://icpcres.ecs.baylor.edu/onlinejudge/index.php?option=com_onlinejudge&Itemid=8&category=10&page=show_problem&problem=834

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.

1 Comment »

RSS feed for comments on this post. TrackBack URI

  1. Tolong bantu codingkan penjumlahan bilangan biner dengan delphi….


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.
Entries and comments feeds.

%d bloggers like this: