C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[19]: 桁不足でしたね… [1]


(過去ログ 18 を表示中)

[トピック内 29 記事 (21 - 29 表示)]  << 0 | 1 >>

■7124 / inTopicNo.21)  Re[15]: Long型の乱数を生成する自作クラスをつくりたい
  
□投稿者/ れい (90回)-(2007/08/30(Thu) 14:47:09)
No7120 (ぼのぼの さん) に返信
> ■No7112 (れい さん) に返信
> そんなの関係ねぇ!と言ってしまうのは簡単ですが。

まぁそれならそれで。

> ■No7110 (れい さん) に返信
>>考え方は正解です。
>>
>>(中略)
>>
>>コードは…変です。
>
> やっぱり気になりますね(^^;

・whileが一回も実行されないときのulは?(乱数はもう入ってるならOK
・Convert.ToUInt64って丸めるけどだいじょうぶ?

の辺りです。

あと質問です。
Decimalを使わないのはポリシーですか?
遅いからですか?
Long-ULong変換なんかはDecimal使えばコードは綺麗ですよ。
私は速度を測ったことがないのですが、
自分で書く価値があるほど遅いのでしょうか。

>Dim b() As Byte = BitConverter.GetBytes(0UL)
これは、魔界の仮面弁士さんのポリシーでしょうか?
Dim b(8) As Byteでは遅いのかな?
この心を是非教えてください。

私のコードだとDecimal使いまくりDim x(xx)使いまくりなんですよね。
Redimも使うし。
だめなのだろうか…。
引用返信 編集キー/
■7128 / inTopicNo.22)  Re[16]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ ぼのぼの (83回)-(2007/08/30(Thu) 15:24:11)
No7124 (れい さん) に返信
> ・whileが一回も実行されないときのulは?(乱数はもう入ってるならOK
コードは、■No7041のものがベースなので、Whileの前に一度サイコロ振ってます。
なのでこの点は無問題です。

> ・Convert.ToUInt64って丸めるけどだいじょうぶ?
これは大丈夫じゃないです。てっきり切り捨てるものとばかり… orz
どうやら\演算子は切り捨てのようなので、ここは

While UInt64.MaxValue Mod (divVal) <> (umax - umin) _
AndAlso (ul \ divVal) = (UInt64.MaxValue \ divVal)

とすれば良さそうですね。

> あと質問です。
> Decimalを使わないのはポリシーですか?
> 遅いからですか?
> Long-ULong変換なんかはDecimal使えばコードは綺麗ですよ。
> 私は速度を測ったことがないのですが、
> 自分で書く価値があるほど遅いのでしょうか。

単純に、MSDNに
http://msdn2.microsoft.com/ja-jp/library/xtba3z33(VS.80).aspx
>Decimal は、すべての数値型の中で最もパフォーマンスの低いデータ型です。
>データ型を選択する前に、精度の重要性とパフォーマンスとを比較検討する必要があります。

と書いてあったので、今回は使わないでやってみよう!と思っただけです。
低いとはいえ、余程の回数繰り返して使わない限り人間が体感できるほどの差はでないとは思います。
が、Long-ULong変換はDecimalを使わなくてもそんなに汚くならなかったので。

> >Dim b() As Byte = BitConverter.GetBytes(0UL)
> これは、魔界の仮面弁士さんのポリシーでしょうか?
> Dim b(8) As Byteでは遅いのかな?
> この心を是非教えてください。

これに関しては、私はコピっただけなのでなんとも言えないですね(^^;
ただ、使わせて頂いた側としてはDim b(8) As Byteと書かれるより理解し易い、とは思います。

引用返信 編集キー/
■7131 / inTopicNo.23)  Re[17]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ れい (91回)-(2007/08/30(Thu) 15:42:44)
No7128 (ぼのぼの さん) に返信
> ■No7124 (れい さん) に返信
>>あと質問です。
>>Decimalを使わないのはポリシーですか?
> 
> 単純に、MSDNに
> http://msdn2.microsoft.com/ja-jp/library/xtba3z33(VS.80).aspx
> >Decimal は、すべての数値型の中で最もパフォーマンスの低いデータ型です。
> 
> と書いてあったので、今回は使わないでやってみよう!と思っただけです。
> 低いとはいえ、余程の回数繰り返して使わない限り人間が体感できるほどの差はでないとは思います。
> が、Long-ULong変換はDecimalを使わなくてもそんなに汚くならなかったので。

なるほど。
私は型変換が苦手なので、
よくわからなくなったら範囲が大きいので誤魔化してます。よくないですが。

>>>Dim b() As Byte = BitConverter.GetBytes(0UL)
>>これは、魔界の仮面弁士さんのポリシーでしょうか?
> これに関しては、私はコピっただけなのでなんとも言えないですね(^^;
> ただ、使わせて頂いた側としてはDim b(8) As Byteと書かれるより理解し易い、とは思います。

理解し易いですか。
VBの配列の定義の仕方はきっといろんあ意見があるのでしょうね。
これに関しては魔界から本人が降臨されるのを待つことにします。
(何か生贄は必要なのかしら。

さて。
どうも完成したようなので、私の作った物も投げておきます。
正しいかどうかはきちんとした検査に通してないのでわかりません。

本質は一緒ですが、
振り直し判定が若干違います。
Decimal変換が2回、Moduloが2回、後は加減算で、振り直しは比較演算1回にしてあります。
Decimalの遅さは検証していないので何も言えませんが、
割り算のコストは大きいので、なるべく減らしています。

    Public Function [Next](ByVal min As Long, ByVal max As Long) As Long
        If min > max Then Throw New ArgumentOutOfRangeException()
        Dim buf(8) As Byte
        If min = Long.MinValue AndAlso max = Long.MaxValue Then
            _Random.NextBytes(buf)
            Return BitConverter.ToInt64(buf, 0)
        End If
        Dim a As ULong
        Dim range As ULong = CULng(1D + max - min)
        Dim residue As ULong = (ULong.MaxValue - range + 1UL) Mod range
        While (True)
            _Random.NextBytes(buf)
            a = BitConverter.ToUInt64(buf, 0)
            If a >= residue Then Exit While
        End While
        Return CLng(((a - residue) Mod range) + min)
    End Function

引用返信 編集キー/
■7144 / inTopicNo.24)  Re[18]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ ぼのぼの (84回)-(2007/08/30(Thu) 17:19:10)
No7131 (れい さん) に返信
> さて。
> どうも完成したようなので、私の作った物も投げておきます。
> 正しいかどうかはきちんとした検査に通してないのでわかりません。
> (以下略)

をを、ULongとかCULngとか普通にあるのか… orz
ここらへんは、単に知ってるか知らないかだけの話なわけですが、
だいぶコードがスッキリしますね。

>         Dim range As ULong = CULng(1D + max - min)

ここらへんは、初心者だと「あれ?タイプミスじゃね?」と
1Lに直してしまいそうですね(笑)。

しかし、数学に強くないと「何故このロジックでうまくいくのか」を
完全に理解するのは難しいですね。
私ももうちょい時間がかかりそうです…

引用返信 編集キー/
■7154 / inTopicNo.25)  Re[16]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ 魔界の仮面弁士 (397回)-(2007/08/30(Thu) 23:21:57)
2007/08/30(Thu) 23:33:16 編集(投稿者)
No7124 (れい さん) に返信
>> Dim b() As Byte = BitConverter.GetBytes(0UL)
> これは、魔界の仮面弁士さんのポリシーでしょうか?

私も、普段は使いません。(^^;
サンプルですので、可読性を優先させたが故の結果です。

# かえって分かりにくいという人もいるでしょうから、
# 可読性というと語弊があるかも知れませんけれども。


> Dim b(8) As Byteでは遅いのかな?
> この心を是非教えてください。

そういった間違いを防ぐ目的もあります。8 ではないですよね。


=======

で。昔からの VB 使いとしては、いにしえの「Rnd 関数」時代に使われていた
  randomvalue = CInt(Int((upperbound - lowerbound + 1) * Rnd() + lowerbound))
の方式を用いて、こんなのとか。速度面は度外視。



Public Class LongRandom

    Private _Random As New System.Random()

    Public Function [Next](ByVal min As Long, ByVal max As Long) As Long
        If min = max Then Return min
        If min > max Then Throw New ArgumentOutOfRangeException()

        Dim dMin As Decimal = CDec(min)
        Dim dMax As Decimal = CDec(max)
        Dim dRnd As Decimal = Sample()

        '標準の Next 仕様:「Min以上 Max 未満」
        Return CLng(Int(dMin + dRnd * (dMax - dMin)))

        '「Min以上 Max 以下」ならこっち
        'Return CLng(Int(dMin + dRnd * (dMax - dMin + 1D)))
    End Function

    Private Function Sample() As Decimal
        Dim iHi As Integer = _Random.Next(0, 1000000000)
        Dim iLo As Integer = _Random.Next(0, 1000000000)
        Dim s As String = String.Format("0.{0:000000000}{1:000000000}", iHi, iLo)

        ' 0以上1未満の値を返す
        Return Decimal.Parse(s)
    End Function
End Class

引用返信 編集キー/
■7162 / inTopicNo.26)  Re[17]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ ぼのぼの (85回)-(2007/08/31(Fri) 11:03:36)
No7154 (魔界の仮面弁士 さん) に返信
> '標準の Next 仕様:「Min以上 Max 未満」

O...TL

いろいろ穴があいてるなぁ<自分

知識不足、というより調査不足です。面目ない。

とりあえず、1回解決済みマークをつけときます。

レスくださった方々、ありがとうございました。
特にれいさんには何度もダメ出ししていただき、いろいろ勉強になりましたです。

こんだけ得るものがあると、掲示板利用して良かったなぁって思いますね^^
解決済み
引用返信 編集キー/
■7197 / inTopicNo.27)  Re[17]: Long型の乱数を生成する自作クラスをつくりたい
□投稿者/ れい (94回)-(2007/08/31(Fri) 17:40:54)
2007/08/31(Fri) 17:41:52 編集(投稿者)

No7154 (魔界の仮面弁士 さん) に返信
> ■No7124 (れい さん) に返信
> >> Dim b() As Byte = BitConverter.GetBytes(0UL)
>>これは、魔界の仮面弁士さんのポリシーでしょうか?
>
> 私も、普段は使いません。(^^;
> サンプルですので、可読性を優先させたが故の結果です。
>>Dim b(8) As Byteでは遅いのかな?
>>この心を是非教えてください。
>
> そういった間違いを防ぐ目的もあります。8 ではないですよね。

おぉ。
VBはここで7なんでした。
やはりVBは難しい。
C++から脳内変換で頑張るのはいい加減無理があるなぁ。

> '標準の Next 仕様:「Min以上 Max 未満」
> Return CLng(Int(dMin + dRnd * (dMax - dMin)))
>
> '「Min以上 Max 以下」ならこっち
> 'Return CLng(Int(dMin + dRnd * (dMax - dMin + 1D)))

そうそう。
忘れてましたが、私も最初違和感を感じてました。
普通は「未満」ですよね。
でないと変換がめんどくさい。

> Dim iHi As Integer = _Random.Next(0, 1000000000)
> Dim iLo As Integer = _Random.Next(0, 1000000000)
> Dim s As String = String.Format("0.{0:000000000}{1:000000000}", iHi, iLo)

小数点以下18桁の精度で、0以上1未満のDecimalを作っています。
一方、Long型は約19桁の整数です。
ですので、

> Return CLng(Int(dMin + dRnd * (dMax - dMin)))

この変換で精度が足りていません。
これでは乱数として得られないLong型が出てきてしまいます。
最低でも後二桁必要です。
解決済み
引用返信 編集キー/
■7208 / inTopicNo.28)  桁不足でしたね…
□投稿者/ 魔界の仮面弁士 (398回)-(2007/08/31(Fri) 19:06:34)
2007/08/31(Fri) 19:09:28 編集(投稿者)

No7197 (れい さん) に返信
> 忘れてましたが、私も最初違和感を感じてました。
> 普通は「未満」ですよね。
> でないと変換がめんどくさい。

System.Random.Next だと、
 .Next(1, 1)
 .Next(1, 2)
が、いずれも「固定値 1」になる仕様なんですよね。
私は、これはこれで違和感を感じていたりします。

「未満」なら、min = max を許容すべきでは無いように思うので。


> Dim s As String = String.Format("0.{0:000000000}{1:000000000}", iHi, iLo)
> 小数点以下18桁の精度で、0以上1未満のDecimalを作っています。
> 一方、Long型は約19桁の整数です。

おぉっと。こりゃ失敗。(^^;;

Decimal は 27〜28桁 あるので、Long / ULong で良いなら、
とりあえず安直に、乱数をもう一個増やすだけで対応できそうですね。
解決済み
引用返信 編集キー/
■7211 / inTopicNo.29)  Re[19]: 桁不足でしたね…
□投稿者/ れい (95回)-(2007/08/31(Fri) 20:35:44)
2007/08/31(Fri) 21:10:56 編集(投稿者)

No7208 (魔界の仮面弁士 さん) に返信
> ■No7197 (れい さん) に返信
> System.Random.Next だと、
>  .Next(1, 1)
>  .Next(1, 2)
> が、いずれも「固定値 1」になる仕様なんですよね。
> 私は、これはこれで違和感を感じていたりします。

あ。ほんとだ。これは…ひどい。

ごにょっていたら、昔書いた、Randomクラスの問題点を調べた資料を見つけました。
あまりに細かい問題なので、まだWebで見たことはありません。
便乗してここに書いておきます。

(1) Random.Nextは0〜0x7FFFFFFEの値を返す。
(2^31-1)通りであり、intの最大値である0x7FFFFFFFは返さない。
これはドキュメントに書いてある通り。

(2) Random.NextDoubleは0〜0.999999999534339の範囲で4.6566128752457969E-10置きの値しか返さない。
Random.NextDoubleは(Random.Next*4.6566128752457969E-10)と同値。
例えば、Doubleの1未満の最大値である
BitConverter.ToDouble(New Byte() {&HFF, &HFF, &HFF, &HFF, &HFF, &HFF, &HEF, &H3F}
は返さない。

(3) Next(int maxvalue)はRandom.NextDouble*maxvalueと同値。
丸め誤差のせいで、確率分布がおかしい。

(4) Next(int minvalue, int maxvalue)はmaxvalue-minvalueが&H7fffffffより大きいか、小さいかで確率がだいぶ変わる。
小さい場合はNext(int maxvalue)と同じ問題が生じる。
大きい場合はさらに、minとmaxの中間値が出る確率が2倍になる問題が生じる。

(5) Random.NextByteは、&HFFが微妙に少ない。
Random.Nextの下位8bitを取っていることからくる問題。
具体的には 0x7FFFFF/0x800000 = 0.99999988079071044921875
だけ少ない。

RandomはNumerical RecipesのKnuthのコードそのままらしいのですが、
実装にいろいろ問題が在ります。
普通気にならないレベルなのかもしれませんが、
Randomを大規模に使うなら自分で実装したほうがいいですね。
解決済み
引用返信 編集キー/

<前の20件
トピック内ページ移動 / << 0 | 1 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -