楼主: nyfor

[精华] nyfor 复活节比短代码解题说明

[复制链接]
论坛徽章:
10000
绿钻
日期:2016-02-22 15:43:08绿钻
日期:2016-03-01 18:19:01绿钻
日期:2016-02-22 15:43:08绿钻
日期:2016-03-01 18:19:01绿钻
日期:2015-12-16 18:42:35绿钻
日期:2015-12-11 00:18:01绿钻
日期:2015-09-10 13:05:08绿钻
日期:2015-12-11 00:18:01绿钻
日期:2015-09-10 13:05:08绿钻
日期:2015-09-10 13:05:08
11#
发表于 2011-4-27 23:23 | 只看该作者
原帖由 newkid 于 2011-4-27 23:18 发表
为了节省一个BEGIN把初始化代码都移进了过程p,真是极端手段!


大师:请教下?
c(g) := least(0, c(f), c(g));
这步里面用个0作用是什么啊?
有点看不懂,调试了下也没看懂
c(f),c(g)应该都是负值的啊?
不用的0结果却不对

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
12#
发表于 2011-4-27 23:41 | 只看该作者
原帖由 jboracle1981 于 2011-4-27 23:23 发表


大师:请教下?
c(g) := least(0, c(f), c(g));
这步里面用个0作用是什么啊?
有点看不懂,调试了下也没看懂
c(f),c(g)应该都是负值的啊?
不用的0结果却不对

注意c是字符串类型,加个0会强行隐性转换为NUMBER型再比较。

使用道具 举报

回复
论坛徽章:
10000
绿钻
日期:2016-02-22 15:43:08绿钻
日期:2016-03-01 18:19:01绿钻
日期:2016-02-22 15:43:08绿钻
日期:2016-03-01 18:19:01绿钻
日期:2015-12-16 18:42:35绿钻
日期:2015-12-11 00:18:01绿钻
日期:2015-09-10 13:05:08绿钻
日期:2015-12-11 00:18:01绿钻
日期:2015-09-10 13:05:08绿钻
日期:2015-09-10 13:05:08
13#
发表于 2011-4-28 08:06 | 只看该作者
原帖由 newkid 于 2011-4-27 23:41 发表

注意c是字符串类型,加个0会强行隐性转换为NUMBER型再比较。

3Q

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
14#
 楼主| 发表于 2011-4-28 09:34 | 只看该作者
使用了subtype,并将原本int型的变量定义成了varchar型, 故而
f := least(0, c(40), c(41));
z(least(f, c(39)));
z(c(39), 0);
z(f, 30, 1);
这段代码中的
z(least(f, c(39)));
这一行有BUG,还得加上一个常数0.

既然f,g都定义成 w (varchar)型了,故而可以复用 s,x这两个变量.
从而又可以减少6个字节,但是修正上面的BUG需多两个字节,故此次修改可以减少4个字节.

PS: 帖子内容能追加折叠功能吗?不想代码默认的显示出来占大量空间.

长度变为: 1211 byte
create or replace package easter is
  procedure showAllEasterDay;
  procedure showMaxOccurenceEasterDay;
  procedure showLeapEasterDay;
  procedure showFoolEasterDay;
end;
/
create or replace package body easter is
  c dbms_sql.varchar2s;
  subtype w is varchar(999);

  s w;
  x w;
  v date := date '1-3-31';

  procedure p(t w) is
  begin
    dbms_output.put_line(t);
  
    for i in -30 .. 50 loop
      c(i) := 0;
    end loop;
  
    for y in 2011 .. 2099 loop
      x := y - 1900;
      s := x mod 19;
      s := (11 * s + 4 - trunc((7 * s + 1) / 19)) mod 29;
      x := 25 - s - (x + trunc(x / 4) + 31 - s) mod 7;
   
      c(y) := to_char(v + x, ' mm-dd');
   
      c(x) := c(x) - 1;
   
      s := sign(x - 1) + 40;
      c(s) := least(0, c(x), c(s));
    end loop;
    s := '';
  end;

  procedure showAllEasterDay is
  begin
    p('YEAR DAY');
    for y in 2011 .. 2099 loop
      p(y || c(y));
    end loop;
  end;
  procedure z(w w, n w := 30, m w := -30) is
  begin
    for f in m .. n loop
      if c(f) = w then
        s := s || to_char(v + f, 'mm-dd/');
      end if;
    end loop;
    s := rtrim(s, '/') || ' ' || -w || ' ';
  end;
  procedure showMaxOccurenceEasterDay is
  begin
    p('MAXOCC                               MO_CNT MAXOCC_3 MO3_CNT    MAXOCC_4          MO4_CNT');
  
    x := least(0, c(40), c(41));
    z(least(0, x, c(39)));
    z(c(39), 0);
    z(x, 30, 1);
  
    p(s);
  end;
  procedure showLeapEasterDay is
  begin
    p('ABSENT_START ABSENT_END');
    for i in 22 - 31 .. 25 loop
      x := to_char(v + i, 'mm-dd   ');
      if c(i) = 0 then
        s := nvl(s, x);
      end if;
      if s < x and (i = 25 or c(i + 1) < 0) then
        p(s || x);
      end if;
    end loop;
  end;
  procedure showFoolEasterDay is
  begin
    p('YEAR TOTAL');
    for y in 2011 .. 2099 loop
      if substr(c(y), -2) = 1 then
        p(y || ' ' || -c(40));
      end if;
    end loop;
  end;
end;
/

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
15#
发表于 2011-4-28 09:36 | 只看该作者
这么猛,必须加精啊

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
16#
发表于 2011-4-28 09:37 | 只看该作者
考虑的太细致了,这个代码好好研究能学到好多东西,谢谢nyfor

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
17#
 楼主| 发表于 2011-4-28 10:10 | 只看该作者
谢谢 dingjun123
least函数中,为了将字串转换成数字后比较,才用了一个常数0, 之前一直想到字串前面加个 - 号, 可以将整数变成负数,
可没想到加 + 号也是可以的.
故而, 所有 least 函数中需要常数0的地方都可以用+来实现以减少一个字节.
即:least(0, c(x), c(s)) ==> least(+c(x), c(s))

这样一修改,共三个地方, 故而还可以再减少 3 个字节成为 1208 字节.

使用道具 举报

回复
论坛徽章:
32
祖国60周年纪念徽章
日期:2009-10-09 08:28:002013年新春福章
日期:2013-02-25 14:51:24迷宫蛋
日期:2013-06-28 11:09:23ITPUB季度 技术新星
日期:2013-07-30 16:04:58优秀写手
日期:2013-12-18 09:29:132014年新春福章
日期:2014-02-18 16:43:09马上有钱
日期:2014-02-18 16:43:09红孩儿
日期:2014-03-04 16:40:38美羊羊
日期:2015-02-16 16:36:28懒羊羊
日期:2015-03-04 14:52:11
18#
发表于 2011-4-28 10:19 | 只看该作者
真是精益求精啊,nyfor的代码有了最终版了没呢?

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
19#
 楼主| 发表于 2011-4-28 10:34 | 只看该作者
将给定的算法,做等价的转换,并计算一部分中间结果(这个中间结果应该不算破坏规则吧)
原来的:
x := y - 1900;
s := x mod 19;
s := (11 * s + 4 - trunc((7 * s + 1) / 19)) mod 29;
x := 25 - s - (x + trunc(x / 4) + 31 - s) mod 7;
==>
x mod 19 <==> (y - 1900) mod 19 因为1900正好是 19 的整数倍,同时我们的y >= 1900, 故而等价于 y mod 19
trunc(x/4) <==> trunc((y-1900)/4) 同样因为1900正好是 4 的整数倍,同时我们的y >= 1900, 故而等价于 trunc(y/4) - 1900/4

因此我们将第一个赋值表达式去掉, 后面直接用 y 去处理,即得到:
s := y mod 19;
s := (11 * s + 4 - trunc((7 * s + 1) / 19)) mod 29;
x := 25 - s - (y - 1900 + trunc(y / 4) - 1900 / 4 + 31 - s) mod 7;
进一步就是:
s := y mod 19;
s := (11 * s + 4 - trunc((7 * s + 1) / 19)) mod 29;
x := 25 - s - (y - 2344 + trunc(y / 4) - s) mod 7;

此变换将节省 8 字节.最终变成 1200 字节.

使用道具 举报

回复
论坛徽章:
40
授权会员
日期:2009-03-04 17:06:25最佳人气徽章
日期:2013-03-19 17:24:25SQL极客
日期:2013-12-09 14:13:35优秀写手
日期:2013-12-18 09:29:09ITPUB元老
日期:2015-03-04 13:33:34白羊座
日期:2016-03-11 13:49:34乌索普
日期:2017-11-17 11:40:00
20#
发表于 2011-4-28 10:49 | 只看该作者
哇  nyfor 老大 太牛了  

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表