パスワードを忘れた? アカウント作成
この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。

Zuneとgigabeatが閏年の処理の問題でフリーズ」記事へのコメント

  • by Anonymous Coward on 2009年01月01日 23時51分 (#1484260)
    Freescaleの参照ドライバがバグっていた模様です。
    閏年の判断が間違ってたわけじゃなくて、1980年1月1日からの日数を閏年を考慮して年初からの日数に直すところで無限ループに入っていたという…
    http://www.zuneboards.com/forums/zune-news/38143-cause-zune-30-leapyea... [zuneboards.com]
    • by Anonymous Coward on 2009年01月02日 2時08分 (#1484292)
      件のコードでは日数が1年分以上ある場合は1年分の日数を減じて年をひとつ増やすという方法で、年と元日からの日数を算出している訳ですが、if (days > 366) のガード条件の後付けっぽい不自然さが、こんな感じで場当たり的に作られたものな感じを受けます。

      ・年は日数が365以下になるまで365が何回引けたか数えればいいかな
      ・残った日数は次の処理で使えるしね
      ・あれ? うるう年の時は1年は366日だよ!
      ・あぶないあぶない。うるう年の時は366を引くようにして、と
      ・(同僚) ねえ。この処理だと days が減りすぎちゃう時がない?
      ・あ、そうだね。じゃあ、引き過ぎにならないようにif文で確認して、と
      ・ありがとう! これで完璧だよ!

      で、テストしてない、と……

      親コメント
    • by Anonymous Coward on 2009年01月02日 7時08分 (#1484319)
      重箱の隅つつくけど、
      参照ドライバって言い方します?
      リファレンスドライバのことだと思うんですが、あえて言うなら純正ドライバ?基準ドライバ?
      親コメント
      • by Anonymous Coward
        参照実装という言葉は時々聞く気がする。良い訳語だとは思わないけど、とにかく存在する。

        組み込み系とそれ以外との文化の相違の問題である…のかどうかは存じません。
    • by Anonymous Coward
      素直に書けば、これだけのこと?

      year = ORIGINYEAR; /* = 1980 */
       
      while (days > (IsLeapYear(year) ? 366 : 365))
      {
        days -= IsLeapYear(year) ? 366 : 365;
        year += 1;
      }
      • by Anonymous Coward
        教科書的に書けばこんな感じ。

        year = ORIGINYEAR; /* = 1980 */
        year_days = IsLeapYear(year) ? 366 : 365;
        while (days > year_days)
        {
            days -= year_days;
            year += 1;
            year_days = IsLeapYear(year) ? 366 : 365;
        }
        • by Anonymous Coward on 2009年01月02日 3時40分 (#1484307)
          両方とも、「IsLeapYear(year) ? 366 : 365;」が複数箇所に記述されてるのは駄目だろう。
          この程度なら余裕で見通せるだろうが、基本的に同一の記述が複数にあると潜在バグの元になる。
          過去の遺産的なつぎはぎ修正のプログラムは、たいていこんなものが散見されて、コピペミスと思われるバグがあったりするよ。
          親コメント
          • by Anonymous Coward
            つまり、実用的に書くとこんな感じ?

            year = ORIGINYEAR; /* = 1980 */
            while (1)
            {
                if (IsLeapYear(year))
                {
                    if (days <= 366) break;
                    days -= 366;
                }
                else
                {
                    if (days <= 365) break;
                    days -= 365;
                }
                year += 1;
            }
            • by Anonymous Coward
              この場合はforで書いたほうが読みやすいよ。

              for (year = ORIGINYEAR; ; year++)
              {
                  if (IsLeapYear(year))
                  {
                      if (days <= 366) break;
                      days -= 366;
                  }
                  else
                  {
                      if (days <= 365) break;
                      days -= 365;
                  }
              }
              • by Anonymous Coward on 2009年01月02日 9時40分 (#1484333)
                これ、実用的なの?ifの中身を同じアルゴリズムにするのと、ローカル変数を一つ増やすのとの差でしょ?

                for (year = ORIGINYEAR;; year++) {
                  year_days = IsLeapYear(year)? 366 : 365;
                  if (days <= year_days)
                    break;
                  days -= year_days;
                }
                おそらく、組み込み系にとっての、という意味だと思うが…。
                親コメント
              • by Anonymous Coward
                実用性云々じゃなくて、

                        year_days = IsLeapYear(year) ? 366 : 365;

                をうっかり、

                        year_days = IsLeapYear(year) ? 365 : 366;

                と、しちゃったりとか、そういうトラブルを未然に防げる、って事だと思う。
              • by Anonymous Coward
                for文もwhile文も使わない経過日数の計算アルゴリズム [ufcpp.net]もありますね。
                ドキュメンテーションをしっかりしておく必要はありますが。。
              • by Anonymous Coward
                どうしてif文で書くと365と366を書き間違えるトラブルを未然に防げるの?
              • by Anonymous Coward on 2009年01月02日 14時01分 (#1484375)
                三項演算子を知らないプログラマがいるからです。
                保守性を考えた場合、底辺に合わせるしかありません。
                親コメント
              • by Anonymous Coward on 2009年01月02日 14時41分 (#1484385)
                三項演算子も知らないプログラマに保守できるように書いちゃったら自分がクビを切られちゃうじゃないですか!
                管理側の発想としてはとてもよく理解できますけど。
                親コメント
              • by Anonymous Coward
                いや、三項演算の":"に問題がある(?)っていう話なら、ifを使ってこう書き換えてもいいはず。

                for (year = ORIGINYEAR;; year++) {
                  if (IsLeapYear(year))
                    year_days = 366;
                  else
                    year_days = 365;
                 
                  if (days <= year_days)
                    break;
                  days -= year_days;
                }
              • by Anonymous Coward
                days=`date +%j`

                ってのはドライバということだとだめなんでしょうけど、
                なぜに1980年からの通算日数から年内日数なのでしょう? RTCにはBCDで
                月日が格納されるのがほとんどだと思うのですが。

                epochが1980年?とググったらarcプロセッサのシステムで
                採用しているみたいですね。
              • by Anonymous Coward
                ソフトウェアで年月日に変換すればいいのだから、クロックは単なる2進カウンタで実装したほうが、回路のコストが浮きますよ。
                微々たるものですが、ソフトウェアで十分なものをハードウェアでやるのは、どーかと思います。
              • MISRA-Cだと,三項演算子の使用もif-elseでのカッコの省略も,ルール逸脱ってことで文書を上納しなければならなかったりしたような.面倒.

                // 個人的にはコーディングスタンダード嫌いなID
                --
                from もなか
                親コメント
              • by Anonymous Coward
                ちょっとカメだがひとこと。

                > をうっかり、

                バカをいいなさんな。 こういう奴がいるから

                if (is_xxx) {
                /* Nothing to do */
                } else {
                /* Procedure to do */
                }
                とかいうわけのわからない書式が規約になったりする。勘弁してくれ。

                組み込みチップではローカル変数は貴重である上にアクセスすると使うとペナルティがでかかったりするのだよ。
                数多くのレジスタと大量のスタックと高速のメモリが当然だと考えないでくれたまへ。
      • by Anonymous Coward
        この中に、これが今年の(コードの)書き初めって人は何人いるんだろう?
      • by Anonymous Coward
        天文年間で計算方法を調べてみよ
    • by Anonymous Coward
      つまり、このライブラリを作った時に使用したFreescaleのプロセッサが、人間に気が付かれない位に素早く無限ループを処理できる高性能プロセッサだったんですね。
      だから実機に近い環境で確認しろと・・・

身近な人の偉大さは半減する -- あるアレゲ人

処理中...