Reputation: 404
i have the following function that is supposed to return true if the passed argument is a reasonable date and false otherwise. the problem is that it is returning false even for obviously reasonable dates and i can't figure out what is wrong with it. anyone with sharper eyes please help. here it is:
fun reasonable_date(x: int*int*int) =
if #1 x > 0 andalso #2 x > 0 andalso #2 x <= 12 andalso #3 x > 0 andalso #3 x <= 31
then
if #2 x = 1 mod 2 andalso #2 x < 8 andalso #3 x <= 31 then true
else if #2 x = 0 mod 2 andalso #2 x >= 8 andalso #3 x <= 31
then true
else if #2 x = 0 mod 2 andalso #2 x < 8
then
if #2 x = 2 andalso (#3 x = 28 orelse #3 x = 29) then true
else if #2 x = 0 mod 2 andalso #3 x <= 30 then true
else false
else if #2 x = 1 mod 2 andalso #2 x > 8 andalso #3 x <=30 then true
else false
else false
Upvotes: 0
Views: 257
Reputation: 106
i prefer this solution which seems more readable
fun reasonable_date (y, m, d) =
let val daysInMonth =
List.nth([31, if isLeapYear y then 29 else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], m-1)
in
(* Check year >= 1 *)
y >= 1 andalso
(* Check 1 <= month <= 12 *)
(m >= 1 andalso m <= 12) andalso
(* Check 1 <= day <= n, for n being the number of days in specified month *)
(d >= 1 andalso d <= daysInMonth)
end
but may be i missed some tricks (i assume you already wrote an helper function isLeapYear)
Upvotes: -1
Reputation: 5944
Your current solution is impossible to maintain, and its logic looks like something that has been to hell and back :)
I would recommend that you break it up into smaller logical parts that ensure simple properties. Thus instead of first testing whether the year, month and day is greater or equal to one, you could group all the logic regarding years, months and days for itself
fun daysInMonth n =
List.nth([31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], n-1)
fun reasonable_date (y, m, d) =
(* Check year >= 1 *)
y >= 1 andalso
(* Check 1 <= month <= 12 *)
(m >= 1 andalso m <= 12) andalso
(* Check 1 <= day <= n, for n being the number of days in specified month *)
(d >= 1 andalso d <= daysInMonth m)
Obviously this doesn't handle leap years, however that is also quite simple to implement using a helper function, if the month is February. It could be done like this
fun reasonable_date (y, m, d) =
(* Check year >= 1 *)
y >= 1 andalso
(* Check 1 <= month <= 12 *)
(m >= 1 andalso m <= 12) andalso
(* Check 1 <= day <= n, for n being the number of days in specified month *)
(d >= 1 andalso
(* If February, and leap year *)
((m = 2 andalso isLeapYear y andalso d <= 29)
(* Any other month or non leap year *)
orelse d <= daysInMonth m))
Upvotes: 2
Reputation: 25032
You repeatedly use conditions like if #2 x = 1 mod 2
. This is almost certainly does not work as you think it does. Here, mod
is an arithmetic operator, meaning the remainder obtained when dividing 1 by 2, and not the mathematical expression saying that #2 x
equals 1 modulo 2. Thus, instead of testing whether #2 x
is odd, you're testing whether it equals 1. Following through your conditions, you really only allow true
when #2 x
is 1, so your reasonable dates must all be in January (and there may not even be any, I haven't worked through all conditions).
Upvotes: 1