除算・余剰を使わずに閏年
Posted feedbacks - Nested
Flatten Hidden無限リストつかいます。 実行例: *Main> :main 1900 False *Main> :main 2000 True *Main> :main 2008 True *Main> :main 2100 False
1 2 3 4 5 6 7 8 9 10 11 12 | module Main (main) where
import System.Environment
main :: IO ()
main = print . (ys !!) . read . head =<< getArgs
y4s = [True,False,False,False]
y100s = False : tail (take 100 $ cycle y4s)
y400s = True : tail (take 400 $ cycle y100s)
ys = cycle y400s
|
割り切れる数字の部分だけ真で他は偽の値を持つ循環リストを作成し、 周期4、100、400を重ね合せて判定してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 | (defun leap-year-p (y)
(do ((i y (1- i))
(c4 (%clist 4) (cdr c4))
(c100 (%clist 100) (cdr c100))
(c400 (%clist 400) (cdr c400)))
((zerop i) (or (and (car c100) (car c400))
(and (not (car c100)) (car c4))))))
(defun %clist (freq)
(let ((l (make-list freq)))
(setf (car l) t)
(rplacd (last l) l)
l))
|
すいません、紀元前に対応してませんでしたので、修正します…。
1 2 3 4 5 | --- 5333.txt 2008-01-16 07:51:10.085978672 +0900
+++ 5333.txt.fix 2008-01-16 07:51:54.569311280 +0900
@@ -2 +2 @@
- (do ((i y (1- i))
+ (do ((i (abs y) (1- i))
|
正規表現で。 sub judge()はうるう年のとき1、通常年のときは0を返します。 実行結果: $ ./dk124.pl 1900 0 2000 1 2008 1 2100 0
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/bin/perl
sub judge($)
{
$_ = shift;
return 0 != (/(([13579][26])|([02468][048]))00$/ || (!/00$/ && /(([13579][26])|([02468][048]))$/));
}
for (1900, 2000, 2008, 2100) {
printf("%d %d\n", $_, judge($_));
}
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 | | 閏年か? |
閏年か? := [:int |
((0 to: Float infinity by: 4) includes: int)
and: [((0 to: Float infinity by: 100) includes: int) not
or: [(0 to: Float infinity by: 400) includes: int]]].
閏年か? value: 1900. "=> false "
閏年か? value: 2000. "=> true "
閏年か? value: 2008. "=> true "
閏年か? value: 2100. "=> false "
|
考えたら、べつに無限にせずともこれで十分ですね(^_^;)。
1 2 3 4 5 6 7 8 9 10 11 | | 閏年か? |
閏年か? := [:int |
((0 to: int by: 4) includes: int)
and: [((0 to: int by: 100) includes: int) not
or: [(0 to: int by: 400) includes: int]]].
閏年か? value: 1900. "=> false "
閏年か? value: 2000. "=> true "
閏年か? value: 2008. "=> true "
閏年か? value: 2100. "=> false "
|
まあ、こういうのもあるということで。
1 2 3 4 5 6 7 8 9 10 | | 閏年か? |
閏年か? := [:int |
(int isDivisibleBy: 4)
and: [(int isDivisibleBy: 100) not or: [int isDivisibleBy: 400]]].
閏年か? value: 1900. "=> false "
閏年か? value: 2000. "=> true "
閏年か? value: 2008. "=> true "
閏年か? value: 2100. "=> false "
|
とても素朴な書き方。剰余の計算を禁止しても引き算の繰り返しでできてしまいますね。一応、大きい順に引くことで繰り返しの回数を減らしてあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | >>> def leap(x, d=400):
if x < 0:
return leap(-x, d)
if x == 0:
if d == 400:
return True
if d == 100:
return False
if d == 4:
return True
if x < d:
if d == 400:
return leap(x, 100)
if d == 100:
return leap(x, 4)
if d == 4:
return False
return leap(x - d, d)
>>> leap(1900)
False
>>> leap(2000)
True
>>> leap(2008)
True
>>> leap(2100)
False
|
ついにゅっとなってやってしまった。
1 2 3 4 5 6 7 8 9 10 | def leap(x, d=400):
return (
not d and [d]
or
x == 0 and [[1, 0, 1][d >> 6 & 3]]
or
x < d and [leap(x, [0, 4, 100][d >> 6 & 3])]
or
[leap(x - d, d)]
)[0]
|
まあ、かけ算でも出来るわけでして。 #なんか揚げ足取りばっかしているように思われ #ちゃうだろうなぁ。マイナス評価でもしょうがないか。 $ pl -qs 124.pl ?- uru(1900). No ?- uru(2000). Yes ?- uru(2008). Yes ?- uru(2100). No ?-
1 2 3 4 5 6 7 | uru(X):- divideby400(X).
uru(X):- divideby4(X), not(divideby100(X)).
divideby(X, Y, Z) :- 0 =:= X - integer(X * Y) * Z.
divideby4(X) :- divideby(X, 0.25, 4).
divideby100(X) :- divideby(X, 0.01, 100).
divideby400(X) :- divideby(X, 0.0025, 400).
|
一応、条件は満たしているかと思います。 こんな感じでどうでしょうか?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Sample124 {
public static boolean isLeepYear(int year) {
if (!isDividedBy4(year)) return false;
String sYear = String.valueOf(year);
if (sYear.endsWith("00")) {
return isDividedBy4(Integer.parseInt(sYear.substring(0, sYear.length() - 2)));
}
return true;
}
private static boolean isDividedBy4(int num) {
return (num & 3) == 0;
}
public static void main(String[] args) {
System.out.println("1900:" + isLeepYear(1900));
System.out.println("2000:" + isLeepYear(2000));
System.out.println("2008:" + isLeepYear(2008));
System.out.println("2100:" + isLeepYear(2100));
}
}
|
素直にやってみました。 実行結果 ------- A.D. 1900: false A.D. 2000: true A.D. 2008: true A.D. 2009: false A.D. 2100: false -------
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class LeapYear {
public static void main(String[] args) {
System.out.println("A.D. 1900: " + isLeapYear(1900));
System.out.println("A.D. 2000: " + isLeapYear(2000));
System.out.println("A.D. 2008: " + isLeapYear(2008));
System.out.println("A.D. 2009: " + isLeapYear(2009));
System.out.println("A.D. 2100: " + isLeapYear(2100));
}
public static boolean isLeapYear(int aYear) {
return isDivisible(aYear, 4) ? (isDivisible(aYear, 100) ? (isDivisible(aYear, 400) ? true : false) : true) : false;
}
public static boolean isDivisible(int aLeft, int aRight) {
while (aLeft >= aRight) {
aLeft -= aRight;
}
return aLeft == 0;
}
}
|
こういうことかな?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /*うるう年なら1、平年なら0を返す*/
int IsUruuDoshi(int year){
int uruu=0;
int uruu_check[]={800,400,100,40,4,0}; //800,40はループ数短縮用
int count=0;
while(uruu_check[count]){
if(uruu==year){
if(uruu_check[count]==100) return 0;
else return 1;
}
if(uruu+uruu_check[count]>year){
count++;
}else{
uruu+=uruu_check[count];
}
}
return 0;
}
|
にしおさんのを見て引き算のがらくだと思ったので修正。
(失敗投稿を削除しておきましたby管理者)
投稿失敗しました・・・・
引き算に修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | int IsUruuDoshi(int year){
int uruu_check[]={800,400,100,40,4,0}; //800,40はループ数短縮用
int count=0;
while(uruu_check[count]){
if(year){
if(uruu_check[count]>year){
count++;
}else{
uruu-=uruu_check[count];
}
}else{
if(uruu_check[count]==100) return 0;
else return 1;
}
}
return 0;
}
|
1 2 3 | leap(N) :- N < 0, N1 is N + 400, !, leap(N1).
leap(N) :- N >= 400, N1 is N - 400, !, leap(N1).
leap(N) :- N /\ 0b11 =:= 0b00, N \= 100, N \= 200, N \= 300.
|
4の倍数チェック以外、減算で剰余を求めてるだけなんですが。何かアクロバティックな方法でもあるんでしょか?
1 2 3 4 5 6 7 8 9 10 11 12 | bool isLeapYear(int y) {
/* return ((y % 4) == 0) && (((y % 400) == 0) || ((y % 100) != 0)); */
if (y < 0)
y *= -1; /* y = abs(y); */
if ((y & 0x03) != 0x00) /* (y != 4×n) */
return false;
while (y >= 400) { y -= 400; }
if (y == 0)
return true;
while (y >= 100) { y -= 100; }
return (y != 0);
}
|
10進で下4桁を分解できればループする必要すらないのか....なるほどね。
sprintf使わない方法が思いつかんのでダメっぽい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <stdio.h>
int isLeapYear2(int y) {
char sn[20];
int n, low, high;
if (y < 0) { y *= -1; }
n = sprintf(buff, "%d", y);
low = 0; /* 10進数 1~2桁目 */
if (n > 0) { low += (sn[n-1] - '0'); }
if (n > 1) { low += (sn[n-2] - '0') * 10; }
if ((low & 0x03) != 0x00)
return false;
high = 0; /* 10進数 3~4桁目 */
if (n > 2) { high += (sn[n-3] - '0'); }
if (n > 3) { high += (sn[n-4] - '0') * 10; }
return (low != 0) || ((high & 0x03) == 0x00);
}
|
1 2 3 4 5 6 7 | N = 2000
checker = Hash['4', 0, '100', 0, '400', 0]
1.upto(N){|i|
checker.each_key{|k| checker[k] += 1 and k.to_i == checker[k] and checker[k] = 0}
}
evaluate = checker['400'] == 0 || checker['100'] != 0 && checker['4'] == 0
puts "#{N} is a " + (evaluate ? 'bissextile' : 'normal') + ' year.'
|
それぞれの条件を無限リストにした。
1 2 3 4 5 6 7 8 9 10 | isLeapYear x = d !! x
where a = cycle $ True : replicate 3 False
b = cycle $ False : replicate 99 True
c = cycle $ True : replicate 399 False
d = zipWith3 (\a b c -> (a && b) || c) a b c
main = do putStr ">> "
l <- getLine
print $ isLeapYear $ read l
main
|
subが成功したかどうかで処理が分岐します
1 2 3 | def leap?(n)
0 == (3 & n.abs.to_s.sub(/00$/,'').to_i)
end
|
str使っていいのかなぁと。 strで100で割るを実現しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | def div4(n):
return (n >> 2 , n & 3)
def div100(n):
m = str(n)
return (int(m[:-2]), int(m[-2:]))
def uruudoshi(year):
n = div4(year)
if n[1] == 0:
m = div100(year)
if m[1] == 0:
if div4(m[0])[1] == 0:
return 1
else:
return 0
return 1
else:
return 0
if __name__=="__main__":
print uruudoshi(1900)
print uruudoshi(2000)
print uruudoshi(2008)
print uruudoshi(2100)
|
正規表現。
see: Perl正規表現雑技
1 2 3 4 5 6 | def leap?( year )
return false unless /((^|[02468])[048]|[13579][26])$/.match( year.to_s )
return true unless /00$/.match( year.to_s )
return false unless /((^|[02468])[048]|[13579][26])00$/.match( year.to_s )
return true
end
|
正弦関数の周期性を利用しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import std.stdio;
import std.math;
bool isLeapYear(int year){
return abs(sin(year * PI * 0.25)) < 0.0001 &&
abs(sin(year * PI * 0.01)) > 0.0001 ||
abs(sin(year * PI * 0.0025)) < 0.0001;
}
void main(){
writefln(isLeapYear(1900)); // false
writefln(isLeapYear(1978)); // false
writefln(isLeapYear(1988)); // true
writefln(isLeapYear(2000)); // true
writefln(isLeapYear(2001)); // false
writefln(isLeapYear(2008)); // true
}
|
なんか、この解答にはワクワクさせるものがあります。
入力が離散的だから、こういう答えもありなのかー。
余剰を自前で作ってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | year=2000
もし,yearが閏年ならば
"{year}年は閏年です"を表示
違えば
"{year}年は閏年ではありません"を表示
●閏年(yが)
もし((MOD(y,4)=0) && (MOD(y,100)<>0||MOD(y,400)=0))ならば
1で戻る
違えば
0で戻る
●MOD(a,b)
Nとは整数。Xとは整数。Yとは整数
もし(a=b)ならば,0で戻る
もし(a<b)ならば,aで戻る
(2^N<b)の間
N=N+1
X=2^N-b
Y=2^N-1
(a>=2*b)の間
a=X*(a>>N)+AND(a,Y)
もし(a>=b)ならば,a=a-b
aで戻る
|
閏年なら1を、平年なら0を返します☆
1 2 3 4 5 6 7 8 9 10 11 12 | #include<stdio.h>
int isleapyear(int y){
int i = y * 0.01;
return !(y == i * 100 ? i & 3 : y & 3);
}
int main(void){
printf("%d\n", isleapyear(1900));
printf("%d\n", isleapyear(2000));
printf("%d\n", isleapyear(2008));
printf("%d\n", isleapyear(2100));
return 0;
}
|
組み込み「メソッド」は使ってもいいのかな。
(でないとRuby/Smalltalkあたりは解答のしようが無いし)
(でないとRuby/Smalltalkあたりは解答のしようが無いし)
1 2 3 4 5 6 7 | function doukaku124a(y){
return new Date(y, 1, 29).getMonth() < 2;
}
function doukaku124b(y){
return !((y +'').replace(/00$/, '') & 3);
}
|
その手がありましたか!って、もはや悪のりでしかありませんね(^_^;)。
1 2 3 4 5 6 7 8 | | 閏年か? |
閏年か? := [:int | int asYear daysInYear = 366].
閏年か? value: 1900. "=> false "
閏年か? value: 2000. "=> true "
閏年か? value: 2008. "=> true "
閏年か? value: 2100. "=> false "
|
そうか、その手が。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
>
<xsl:output method="text" />
<xsl:template match="/" >
<xsl:for-each select="1900 to 2100">
<xsl:variable name="thisYear" as="xs:date"
select="xs:date(fn:concat(xs:string(.), '-01-01'))" />
<xsl:variable name="nextYear" as="xs:date"
select="xs:date(fn:concat(xs:string(1+.), '-01-01'))" />
<xsl:if test="fn:days-from-duration($nextYear - $thisYear)=366">
<xsl:value-of select="." />
<xsl:text> 年は閏年♪
</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
|
Dateクラスをそのまま使うというのは思いつきませんでした。コロンブスの卵すぎる・・・!
一応正攻法も載せておきますね。
1 2 3 4 5 6 7 | is.leap.year1 <- function(y){
!is.na(ISOdate(y,2,29))
}
is.leap.year2 <- function(y){
y %in% union(setdiff(seq(0,y,4), seq(0,y,100)), seq(0,y,400))
}
|
結果: 1900年 は 平年 1901年 は 平年 1902年 は 平年 1903年 は 平年 1904年 は 閏年 ... ... 2000年 は 閏年 2001年 は 平年 2002年 は 平年 2003年 は 平年 2004年 は 閏年 2005年 は 平年 2006年 は 平年 2007年 は 平年 2008年 は 閏年
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <html>
<head>
<title>除算・余剰を使わずに閏年</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
<!--
//閏年の判断
function isLeap(year) {
var nNum = parseInt((year + '').substr(-4));
while(nNum >= 400) {
nNum -= 400;
}
if(nNum == 0) {
return true;
} else {
while(nNum >= 100) {
nNum -= 100;
}
if(nNum == 0) {
return false;
} else {
while(nNum >= 4) {
nNum -= 4;
}
if(nNum == 0) {
return true;
}
}
}
return false;
}
//getElementByIdの短縮
function $(id) {
return document.getElementById(id);
}
//テスト
window.onload = function() {
var sResult = '';
for(var y=1900; y<2009; y++) {
sResult += y + '年 は ' + (isLeap(y) ? '閏年':'平年') + '<br/>';
}
$('result').innerHTML = sResult;
}
//-->
</script>
</head>
<body>
<input type="text" id="year" value="2008" size="6" />年は
<input type="button" value="閏年?" onclick="alert($('year').value + '年 は ' + (isLeap($('year').value) ? '閏年':'平年'));" />
<br/>
<br/>
結果:<br/>
<div id="result"> </div>
</body>
</html>
|
perlらしく。
Dan the Perl Monger
1 2 3 4 5 | #!/usr/local/bin/perl
use strict;
use warnings;
sub is_leap{!($_[0]&0b1 |





greentea #5245() Rating-1/13=-0.08
see: Wikipedia 閏年
[ reply ]