Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
遅レス。
[go: Go Back, main page]

Hatena::Diarytri はてなブックマーク はてなフォトライフ
    
はてな
 ようこそゲストさん  最新の日記 ユーザー登録 ログイン ヘルプ

遅レス。 このページをアンテナに追加 RSSフィード

2005-12-12

[] 整数の除算 このエントリーを含むブックマーク

ショック!

$ perl -e 'print 10 / 3, "\n"'
3.33333333333333

あうあう、知らなかった……。私ぁ今までどうやって生きてきたんだろう。


で、3 を得るには、正規表現置換かなんかで "." 以降削るのが良いの?

もっとスマートな方法はないべか?

$ perl -e '
my $n = 10 / 3;
print $n, "\n";
$n =~ s/\..*$//;
print $n, "\n";
'
3.33333333333333
3

これってダサイよねぇ。

[] Perl整数の除算ツアー (Re: 整数の除算) このエントリーを含むブックマーク

皆さんよってたかってありがとうございます。お礼といっては何ですが全て試してみてみます。


まずは、一番メジャーな方法らしい。というか、やってたけど忘れてた。

int

$ perl -e 'print int(10 / 3)'
3

$ perl -Minteger -e 'print 10 / 3'
3

おっふおっふ(鳴き声) 'use integer;' なんてあるのか、ちょっと興奮。


しかし桁溢れると弱い。

$ perl -e 'print int(-6.725/0.025)'
-268

「わかってる分には、簡単なの使ったらええやろ」って感じが なかだ さんっぽい。


せっかくなのでドキュメントも読んどくか。

$ perldoc -f int
  int EXPR
  int Returns the integer portion of EXPR.  If EXPR is omitted, uses
      $_.  You should not use this function for rounding: one because
      it truncates towards 0, and two because machine representations
      of floating point numbers can sometimes produce counterintu-
      itive results.  For example, "int(-6.725/0.025)" produces -268
      rather than the correct -269; that's because it's really more
      like -268.99999999999994315658 instead.  Usually, the
      "sprintf", "printf", or the "POSIX::floor" and "POSIX::ceil"
      functions will serve you better than will int().

ふむ、通常は int より sprintf, printf, POSIX::floor, POSIX::ceil を使えとな。


順に追ってみよう。


sprintf

$ perl -e 'print sprintf("%d", -6.725/0.025)'
-268

これ、ひょっとして int と一緒じゃね? ソースまで見に行かないけど。


恥ずかしながら、floor とか ceil とか知らなかったので調べた。

floor
〜以下で最大の整数:
ceil
〜以上で最小の整数

らしい。単純に切り下げ・切り上げで考えてると負の時痛い目みれるそうだ。

POSIX

$ perl -MPOSIX -e 'print POSIX::floor(10 / 3)'
3

$ perl -MPOSIX -e 'print POSIX::floor(-10 / 3)'
-4

$ perl -MPOSIX -e 'print POSIX::ceil(10 / 3)'
4

$ perl -MPOSIX -e 'print POSIX::ceil(-10 / 3)'
-3

id:kidd-number5 さんご紹介の perlfaq4 もこれと同じ「POSIX 使え」ですね。


POSIX 族は名前からして C ライブラリを呼び出してるっぽいから、double の範囲を越えると id:lyokato さんのいうように精度の問題が出そう。場合によるな。四捨五入はないみたい。別に Math::Round なんてあるみたいだけれど。


id:lyokato さんから Math::BigFloat 版。これが一番確実。

$ perl -MMath::BigFloat -e 'print Math::BigFloat->new(-6.725/0.025)->bfloor'
-269

でかい数値用の floor。

$ perl -MMath::BigFloat -e 'print Math::BigFloat->new(-6.725/0.025)->bceil'
-269

でかい数値用の ceil。

$ perl -MMath::BigFloat -e 'print Math::BigFloat->new(-6.725/0.025)->bfround(1)'
-269

小数点第1位で四捨五入。Math::BigFloat には四捨五入もしっかりあるんですな。


id:tokuhirom さんご紹介のにぽたん研究所から正規表現

$ perl -e '
(my $d = -6.725/0.025) =~ s/^([-+]?\d+)(?:\.\d+)?$/$1/ee;
print $d;
'
-269

ハッカー臭くてカコエぇー。プロダクションコードなんでやりませんが。といいつつ私には一番わかりやすかったり。バッサリスッキリ。


今、動いてるコードは正規表現版(わはぁー)ですが int に改めようと思います。引いてくる元のデータベースの該当カラムが int(1) なので 0 から 9 までしかありえないから大丈夫でしょう。求めたいものは C や Ruby で言うところの "(n + 1) / 2" です。

+-----+---+---+---+---+---+---+---+---+---+
| var | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+-----+---+---+---+---+---+---+---+---+---+
| ans | 1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 |
+-----+---+---+---+---+---+---+---+---+---+

(0 の場合は「あってたまるか、元データが悪い」という態度)


後続 Perler のためにウマく纏められると良かったんだけど、何せ色々と素養が足りないもので……スンマヘン。あー、眠くてオチも思いつきません。ごめんなさい。

# kidd-number5 『はじめまして

これかなあ・・・。
http://perldoc.perl.org/perlfaq4.html#Does-Perl-have-a-round()-function%3f--What-about-ceil()-and-floor()%3f--Trig-functions%3f』

# lyokato 『こんにちは。
Math::BigFloat->new( 10 / 3 )->bfround(1)
ってのはどうでしょう。』

# lyokato 『あー、四捨五入じゃないんですね
->bfround(1)じゃなくて->bfloor()ですかね
POSIX::floor とかは精度の問題があるので
でかい数値使うときは怖いです。』

# なかだ 『int(10/3)』

# なかだ 『あるいは use integer;』

# tokuhirom 『http://blog.livedoor.jp/nipotan/archives/18935329.html』

# kdmsnr 『最近ハテナオヤメソッドになってる』

# babie 『いかんなぁ、妄想度を上げなきゃ。』