Thông báo

Collapse
No announcement yet.

Tính âm lịch từ dương lịch bằng phương pháp tra bảng [ngôn ngữ C]

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • Tính âm lịch từ dương lịch bằng phương pháp tra bảng [ngôn ngữ C]

    Ý tưởng
    Sau một thời gian đọc và suy ngẫm các bài viết của anh [MENTION=125068]pctcom[/MENTION] và anh [MENTION=204111]thangbk92[/MENTION]. Dâng nhận thấy với giải pháp dùng bảng tra này, vi điều khiển thực hiện rất nhanh, và đơn giản hơn nhiều so với tính trực tiếp như của cụ Hồ Ngọc Đức, tuy nhiên giải thuật của các anh đều chưa thật chính xác. Thế nên hôm nay Dâng sẽ trình bày một giải thuật mới phát triển từ ý tưởng của hai anh trên. Mục tiêu của giải thuật mới này là:
    1. Nâng cao độ chính xác của giải thuật
    2. Giảm kích thước của bảng tra.

    Mục tiêu thứ nhất thì Dâng không đảm bào được (chỉ là tương đối thôi và Dâng cảm thấy như vậy), mục tiêu thứ 2 Dâng đảm bảo sẽ đạt được. Để lưu thông tin của mỗi tháng Dâng chỉ dùng 2 bytes thôi. Như vậy nếu bảng tra 100 năm (từ 1/1/2000 đến 31/12/2099) thì chỉ cần khoảng 2.4 kbytes. Cụ thể, trong mỗi tháng, các thông tin cần lưu là:
    1. Ngày âm lịch đầu tháng dương lịch (N_AL_DT_DL). Do mỗi tháng âm lịch có khoảng từ 29÷30 ngày, nên biến này lưu trong 5 bits.
    2. Tháng âm lịch đầu tháng dương lịch (T_AL_DT_DL). Do tháng có giá trị từ 1÷12, nên biến này lưu trong 3 bits.
    3. Số ngày cảu tháng âm lịch đầu tháng dương lịch (SN_CT_AL). Do tháng âm lịch 29 hoặc 30 ngày, nên biến này lưu trong 1 bit (0 là 29 ngày, 1 là 30 ngày).
    4. Còn một biến thứ 4, biến này chỉ cần dùng 1 bit, còn chức năng của nó Dâng sẽ nói sau.
    Như vậy tổng cộng Dâng dùng 5 + 4 + 1 + 1 = 11 bits cho mỗi tháng. Còn dư 5 bits (so với mục tiêu 2 byte ban đầu đặt ra), do đó Dâng sẽ lưu tiếp biến thứ 5.
    5. Số ngày của tháng dương lịch (SN_CT_DL). Do số ngày của tháng dương lịch chỉ có thể là 28, 29, 30 hoặc 31 nên chỉ cần 2 bít (00 cho 28, 01 cho 29, 10 cho 30 và 11 cho 31). Trong giải thuật này không hề sử dụng biến thứ 5 này, nhưng vẫn để sẵn trong bảng tra cho những lúc cần dùng (cho chức năng hiệu chỉnh ngày tháng chẳng hạn).
    Như vậy vẫn còn dư 2 bits không biết để làm gì nữa, thì đành bỏ trống vậy.

    Giải thuật
    Dâng chia tháng thành hai loại tháng như sau:
    1. Tháng bình thường: Là tháng có nhiều nhất 1 lần chuyển đổi tháng âm lịch. Đa số các tháng thuộc loại này. Ví dụ tháng 6/2000, có một lần chuyển đổi tháng âm duy nhất (từ tháng 4 sang tháng 5). Xem hình ở dưới:


    Với tháng bình thường này, cách xác định ngày tháng âm lịch rất dễ.

    Ngày âm = Ngày dương + Ngày âm lịch đầu tháng dương lịch - 1;
    Nếu ngày âm <= Số ngày của tháng âm lịch đầu tháng dương lịch thì giữ nguyên ngày âm và tháng âm = tháng âm lịch đầu tháng dương lịch
    Ngược lại ngày âm = ngày âm - số ngày của tháng âm lịch đầu tháng dương lịch và tháng âm = tháng âm lịch đầu tháng dương lịch của đầu tháng tháng dương lịch tiếp theo (tra được trong thông tin của tháng kế). Không lấy tháng âm lịch của tháng dương lịch + 1 nhé, nó sẽ sai trong trường hợp tháng âm lịch bị nhuận hoặc tháng âm lịch là tháng 1.

    2. Tháng dị thường: Là tháng có 2 lần chuyển đổi tháng âm lịch. Ví dụ tháng 7/2000, có hai lần chuyển đổi tháng âm lịch, lần thứ nhất là từ tháng 5 sang tháng 6 và lần thứ hai là từ tháng 6 sang tháng 7. Xem hình:


    Có rất nhiều tháng dị thường từ năm 1949 trở về sau: 5/2049, 7/2057, 8/2065, 5/2068, 3/2071, 8/2084, 7/2095

    Tháng dị thường sẽ có cách tính riêng. Vì vậy, ta phải tìm cách nhận ra đâu là tháng dị thường.

    Nếu (Ngày âm lịch đầu tháng dương lịch == số ngày của tháng âm lịch đầu tháng dương lịch) && (Ngày âm lịch đầu tháng dương lịch của tháng tiếp theo == 2) thì đó là tháng dị thường.

    Cái này Dâng ngồi bóc lịch mấy năm mới kết luận được.

    Xác định được tháng dị thường rồi thì tính ngày tháng âm lịch cho nó là không khó.

    Nếu ngày == 1 thì ngày âm lịch = Ngày âm lịch đầu tháng dương lịch và tháng âm lịch bằng = tháng âm lịch đầu tháng dương lịch.

    Nếu ngày == 31 thì ngày âm lịch = 1 và tháng âm lịch = Tháng âm lịch đầu tháng dương lịch của tháng tiếp theo.

    Các ngày còn lại, ngày âm lịch = ngày - 1. Còn tháng âm lịch làm sao tính???

    Nếu tháng âm lịch đầu tháng dương lịch của tháng tiếp theo - tháng âm lịch đầu tháng dương lịch của tháng hiện tại == 2 thì thâng âm lịch = tháng âm lịch đầu tháng dương lịch hiện tại - 1. Nhưng nếu tháng âm lịch đầu tháng dương lịch của tháng tiếp theo - tháng âm lịch đầu tháng dương lịch của tháng hiện tại == 1 thì tháng âm lịch hiện tại là tháng âm lịch nhuận và nó có thể bằng tháng âm lịch của đầu tháng dương lịch hiện tại hoặc bằng tháng âm lịch của đầu tháng dương lịch tiếp theo, không có cách gì xác định được cả. Lúc này ta sử dụng tới biến thứ 4 của bảng tra, biến này quy ước, nếu nó bằng 1 thì tháng âm lịch = tháng âm lịch của đầu tháng dương lịch hiện tại, nếu nó bằng 0 thì tháng âm lịch = tháng âm lịch của đầu tháng dương lịch của tháng tiếp theo. Và biến này mình đặt tên là Tháng Nhuận Bằng Tháng Hiện Tại (TN_B_THT).

    Sau khi xác định được ngày tháng thì năm âm lịch rất dễ tính:
    Nếu tháng âm lịch <= tháng dương lich thì năm âm lich = năm dương lịch
    Ngược lại thì năm âm lịch = năm dương lịch - 1

    Ví dụ minh họa giải thuật
    Ví dụ với tháng 6/2000 (xem hình phía trên) thì các thông tin cần lưu sẽ là:
    N_AL_DT_DL = 29
    T_AL_DT_DL = 4
    SN_CT_AL = 29 (lưu là 0 trong bảng)
    TN_B_THT = 0 (đây không phải là tháng dị thường nên giá trị này là 0 hay là 1 gì cũng được)
    SN_CT_DL = 30 (lưu là 2 trong bảng tra)

    Với tháng 7/2000 (xem hình phía trên) thì các thông tin cần lưu sẽ là:
    N_AL_DT_DL = 30
    T_AL_DT_DL = 5
    SN_CT_AL = 30 (lưu là 1 trong bảng)
    TN_B_THT = 0 (đây là tháng dị thường nhưng không phải là tháng nhuận nên giá trị này là 0 hay là 1 gì cũng được)
    SN_CT_DL = 31 (lưu là 3 trong bảng tra)

    Với tháng 8/2000
    N_AL_DT_DL = 2
    T_AL_DT_DL = 7
    SN_CT_AL = 29 (lưu là 0 trong bảng)
    TN_B_THT = 0
    SN_CT_DL = 31 (lưu là 3 trong bảng tra)

    Đang lưu bài viết tự dưng "Cúp điện" có điện lại thì mở lên chỉ còn có nửa bài. Các MOD có cách nào cho Dâng lấy lại bài trước khi Lưu nửa chừng do cúp điện không?? Giờ mà viết lại viết không nỗi nữa.....
    Last edited by dangemailbox; 20-02-2014, 18:39.

  • #2
    Thôi khỏi bàn giải thuật nữa, mình làm xong thư viện tra lịch âm rồi, các bạn download ở đây:

    Thư viện Solar2Lunar.
    (Chỉ gồm file *.h và file *.c)
    Project để test trên Keil C. (Debug bằng Keil C hoặc chạy mô phỏng bằng Proteus)
    Phầm mềm tạo Bảng tra lịch âm

    Dâng kiểm tra cũng hơi bị kỹ rồi, các bạn yên tâm.
    Last edited by dangemailbox; 21-02-2014, 02:16.

    Comment

    Về tác giả

    Collapse

    dangemailbox Tìm hiểu thêm về dangemailbox

    Bài viết mới nhất

    Collapse

    • mèomướp
      Trả lời cho Sửa bộ nguồn DC 60V 45A
      bởi mèomướp
      Dạ hông dám làm thì chắc chắn sẽ mãi ko thể làm được đâu ạ. Nguồn xung dân dụng vài kw giờ rất nhìu ạ, sạc ô tô điện, máy hàn, lò vi sóng, âm ly... tùy chất lượng mà độ phức tạp sẽ khác nhau ạ. Và cái giá phải trả về kinh tế...
      Hôm qua, 13:11
    • tuyennhan
      Trả lời cho Sửa bộ nguồn DC 60V 45A
      bởi tuyennhan
      Sửa dạng này thì chuyên còn không dám chắc khộng cháy nổ với linh kiện bán ngoài chợ nói gì khộng chuyên .
      Hôm qua, 09:25
    • tuyennhan
      Trả lời cho Cần tư vấn cải thiện chất âm thanh loa SoNy.
      bởi tuyennhan
      Đúng rồi chọn mua theo tai . ca thì phải toàn dải nhạc thì chỉ cao và thấp thé nên loa ca thì nghe nhạc không hay và ngược lại .
      Muốn ca và nhạc đều hay thì phải dúng 2 giàn , còn nếu chỉ có 1 thì phải chỉnh sửa lại sao cho ca và nhạc đều được không quá dở ....
      Hôm qua, 09:10
    • Ng.Phuong.5
      Vấn đề in lỗ khoan ra pdf ở Orcad 9.2
      bởi Ng.Phuong.5
      Vấn đề cũ: khi in mạch ra pdf và bấm chọn Keep Drill Holes Open, in ra thì pdf trắng đen các lỗ chân linh kiện như nhau. Mặc dù có linh kiện phần Drill là 1mm, có linh kiện thì là 3mm. Cho em hỏi cách sửa phần này ở Orcad 9.2 với ạ.
      Mấy con...
      09-01-2025, 19:44
    • viettinh
      Trả lời cho Cần tư vấn cải thiện chất âm thanh loa SoNy.
      bởi viettinh
      Bác nói đúng quá. Cơ mà muốn mua hàng chính hãng, hàng thương hiệu mà tai lại hợp hàng tầu mới khổ chứ.
      Đang tính mua cái loa tầu nữa cột đằng sau loa này, Loa sony chỉ để hát nhép thôi, có dc k các bác ...
      09-01-2025, 18:12
    • nguyendinhvan
      Trả lời cho Cần tư vấn cải thiện chất âm thanh loa SoNy.
      bởi nguyendinhvan
      Theo tôi thì khi hpj sản xuất ra cái loa đó, đã có nhiều chuyên gia kỹ thuật hiệu chỉnh, tính toán các phần tử kỹ lưỡng rồi.
      Bây giờ tính toán hiệu chỉnh lại cần có đội ngũ tương đương với nhà sản xuất.
      Cách đơn giản...
      09-01-2025, 00:04
    • mèomướp
      Trả lời cho Sửa bộ nguồn DC 60V 45A
      bởi mèomướp
      Dạ cháu có ý tốt muốn động viên chú ấy ngâm cứu khoa học thôi ạ. Về phần kiểm tra dao động thì chú ấy chưa biết thì sẽ tìm hiểu được là cần những gì ạ, chắc chắn là khi hướng dẫn phần ấy các cô chú nào đó sẽ lưu ý cần loại sò công suất ra tránh cháy nổ rồi ạ....
      08-01-2025, 19:02
    • tuyennhan
      Trả lời cho Sửa bộ nguồn DC 60V 45A
      bởi tuyennhan
      Chủ thớt hỏi có kiểm tra được dao động mà không cấp nguồn thì rõ trình ở mức nào mà mèo còn xúi ngâm cứu nữa ác vậy ....
      08-01-2025, 15:43
    • tuyennhan
      Trả lời cho Cần tư vấn cải thiện chất âm thanh loa SoNy.
      bởi tuyennhan
      Loa bass đấu trực tiếp không qua phân tần để thành loa toàn dải xem có thoát tiếng khộng , nếu không thoát cần phải sửa lại mạch cs hay âm sắc nếu đủ trình còn nếu thoát ca hay nhưng chưa vừa ý vì bass kém chăc thì đấu lại như cũ và đấu thêm loa mid treble bên ngoài .
      08-01-2025, 15:28
    • mèomướp
      Trả lời cho Cần tư vấn cải thiện chất âm thanh loa SoNy.
      bởi mèomướp
      Dạ loa tép bé xíu như ngón chân cái thôi ạ. Thiếu gì chỗ để đâu. Quan trọng là gắn thêm nó loa nghe ok hay ko thôi ạ...
      08-01-2025, 11:44
    Đang tải...
    X