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

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

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

全過去ログを検索

<< 0 | 1 >>
■91927  Re[11]: C++からVBへの変換
□投稿者/ えんえん -(2019/08/10(Sat) 10:16:21)
    ありがとうございます。
    
    
            For r As Integer = 0 To n - 1 Step n_radix
    
                fft(n_radix, theta * radix, tmpr, tmpi, ar, ai, r_st + r)
    
            Next r
    
    としてみましたが、
    それでも、やはり正しい結果は得られないのですが、なぜでしょうか?
    
    
    配列はByValやByRefを指定しなくとも
    参照型(ByRef)で渡されることは知っていますが
    後から、コードを見たときに分かりやすくするために
    一応、付けています。
    
    ちなみに、普通は配列にはByValやByRefを付けないものなのでしょうか?
    
    ReturnはFunctionのためのもので、
    Exit Sub はSubのためのものだと思っていました。
    
    仰る通り、長い間VBAを使ってきましたので、
    その名残が残っています。
    
    
    
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91930  Re[12]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/10(Sat) 14:19:15)
    No91927 (えんえん さん) に返信
    > それでも、やはり正しい結果は得られないのですが、なぜでしょうか?

    「ar と ai」「tmpr と tmpi」は、再帰処理のたびに入れ替わりますよね。
    ざっと見た感じでは、入れ替えた際の添字管理に問題があるように見えます。


    話を単純化するため、元の処理を下記のように置き換えてみましょう。

     void Proc(int x[], int y[])
     {
      if (x[0] != 0) Proc(&y[1], x);
     }
     void main()
     {
      int ar1[4] = { 11, 22, 33, 0 };
      int ar2[4] = { 55, 66, 77, 0 };
      Proc(ar1, ar2);
     }

    この場合、ポインタは以下のように遷移しますよね。
    この動作をポインタ代わりの r_st% で管理しようとして、失敗しているように見えます。

     main から渡す実引数は
      ar1 が { 11, 22, 33, 0 }
      ar2 が { 55, 66, 77, 0 }
     → C++ の main から呼び出された Proc の仮引数
      x は { 11, 22, 33, 0 }
      y は { 55, 66, 77, 0 }
     →→→ 1 回目の再帰処理で呼ばれた Proc の仮引数
      x は { 66, 77, 0 }
      y は { 11, 22, 33, 0 }
     →→→→ 2 回目の再帰処理で呼ばれた Proc の仮引数
      x は { 22, 33, 0 }
      y は { 66, 77, 0 }
     →→→→→ 3 回目の再帰処理で呼ばれた Proc の仮引数
      x は { 77, 0 }
      y は { 22, 33, 0 }
     →→→→→→ 4 回目の再帰処理で呼ばれた Proc の仮引数
      x は { 33, 0 }
      y は { 77, 0 }
     →→→→→→→ 5 回目の再帰処理で呼ばれた Proc の仮引数
      x は { 0 }
      y は { 33, 0 }
     ←←←←←← 再帰が終わって呼び出し元(4 回目)に戻る
      x は { 33, 0 }
      y は { 77, 0 }
     ←←←←← 再帰が終わって呼び出し元(3 回目)に戻る
      x は { 77, 0 }
      y は { 22, 33, 0 }
     ←←←← 再帰が終わって呼び出し元(2 回目)に戻る
      x は { 22, 33, 0 }
      y は { 66, 77, 0 }
     ←←← 再帰が終わって呼び出し元(1 回目)に戻る
      x は { 66, 77, 0 }
      y は { 11, 22, 33, 0 }
     ←← 再帰が終わって最初の呼び出しに戻る
      x は { 11, 22, 33, 0 }
      y は { 55, 66, 77, 0 }
     ← C++ の main まで戻ってきて
      ar1 が { 11, 22, 33, 0 }
      ar2 が { 55, 66, 77, 0 }



    > 配列はByValやByRefを指定しなくとも
    > 参照型(ByRef)で渡されることは知っていますが

    いろいろごちゃ混ぜになっているような。

    ByVal / ByRef の省略の話と、配列であるかどうかは無関係ですし、
    ByVal / ByRef の話と 値型 / 参照型 の話も別物ですよ。


    > 後から、コードを見たときに分かりやすくするために
    > 一応、付けています。

    『値渡し』を望むなら、ByVal は省略しようと明示しようと、どちらでも構わないと思います。
    自分の場合、新規開発ならば省略表記にした方がスッキリするので記述しませんが、
    VBA からの移行であれば、明示的に記述して移植時の意図を明確にするようにしています。

    一方、『参照渡し』を望むなら、VBA とは違って、ByRef を明示する必要があります。
    しかし ByRef を付けた理由が「配列だから」というのなら、使い方が間違っています。


    > ちなみに、普通は配列にはByValやByRefを付けないものなのでしょうか?
    配列かどうかは一切関係ありません。

    使い分けの方針としては、「出力引数」として実装する場合に限って ByRef を使い、
    それ以外の場合は全て、値渡しとして処理させるのが普通です。

    ただ、出力引数を使うことがそもそも稀であるため、.NET Framework のライブラリで見ても、
    ByRef が利用されているものは殆どありません。使うとしても TryParse メソッドぐらいのものでしょう。
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91932  Re[13]: C++からVBへの変換
□投稿者/ 774RR -(2019/08/10(Sat) 15:02:41)
    全然どうでもいいけど

    オイラが C++ と C# で同じ処理をさせたら性能が団地だった例
    http://bbs.wankuma.com/index.cgi?mode=al2&namber=78124&KLOG=132

    FFT なんぞテキトーに探せばいくらでもライブラリが転がっているような気のせいがする。
    わざわざ詳しくない言語で書かれているプログラムを移植するまでもない。
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91933  Re[14]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/10(Sat) 16:23:56)
    2019/08/10(Sat) 16:26:50 編集(投稿者)

    No91932 (774RR さん) に返信
    > FFT なんぞテキトーに探せばいくらでもライブラリが転がっているような気のせいがする。

    この辺にありそうな気がします。確認はしていませんけど。
    https://www.nuget.org/packages?q=fft

    VB.NET に移植済みの実装が欲しいという話なら、こんなのもあります。
    http://numeric.world.coocan.jp/computer/vb/mathpack.htm

    Excel VBA でも良ければこんなのもありました。
    関数化はされていないものの、再帰処理を用いないフラットな実装。
    http://tsuyu.cocolog-nifty.com/blog/2007/03/publi.html


    真面目に再実装する気があるなら、複素数構造体を併用すると良いかもしれません。
    https://docs.microsoft.com/ja-jp/dotnet/api/system.numerics.complex.frompolarcoordinates

    複素数構造体を用いた実装例は下記にありました。
    F# なので参考にはしにくいかもしれませんが。
    http://www.fssnip.net/dC/title/fast-Fourier-transforms-FFT-



    No91927 (えんえん さん) に返信
    > For r As Integer = 0 To n - 1 Step n_radix
    >   fft(n_radix, theta * radix, tmpr, tmpi, ar, ai, r_st + r)
    > Next r
    > としてみましたが、
    > それでも、やはり正しい結果は得られないのですが、なぜでしょうか?

    オリジナル版にある
     fft(n_radix, theta * radix, &tmpr[r], &tmpi[r], ar, ai);
    ってのは
     fft(n_radix, theta * radix, &tmpr[r], &tmpi[r], &ar[0], &ai[0]);
    でもあるわけですし、再帰で tmpX と aX が入れ替わる点が肝かと思います。

    すなわち、index の offset は r_st 一つでは足りなくて、
    a 系と tmp 系の両方に対して用意すべきかと思います。
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91934  Re[15]: C++からVBへの変換
□投稿者/ えんえん -(2019/08/11(Sun) 21:42:09)
    ありがとうございます。
    
    
    二つ変数を使った方法はどうやれば良いか分からなかったので
    とりあえず、先に ArraySegmentを使った方法を試してみました。
    
    
    
    
    
        Public Sub one_D_FFT(ByRef xr#(), ByRef xi#())
    
    
            Dim n As Integer = xr.GetLength(0) - 1
    
            Dim theta = 2 * Math.PI / n
    
            Dim xr2 As New ArraySegment(Of Double)(xr), xi2 As New ArraySegment(Of Double)(xi)
    
            Dim tmpr(n) As Double, tmpi(n) As Double
            Dim tmpr2 As New ArraySegment(Of Double)(tmpr), tmpi2 As New ArraySegment(Of Double)(tmpi)
    
            Call fft(n, theta, xr2, xi2, tmpr2, tmpi2)
    
    
        End Sub
    
    
    
    
        Private Sub fft(ByVal n%, ByVal theta#, ByRef ar As ArraySegment(Of Double), ByRef ai As ArraySegment(Of Double), ByRef tmpr As ArraySegment(Of Double), ByRef tmpi As ArraySegment(Of Double))
    
            If n <= 1 Then Exit Sub
    
            Dim radix As Integer = 2
            Do While radix * radix <= n
                If n Mod radix = 0 Then Exit Do
                radix += 1
            Loop
    
            If n Mod radix <> 0 Then radix = n
    
            Dim n_radix As Integer = n \ radix
    
            For j As Integer = 0 To n_radix - 1
    
                For m As Integer = 0 To radix - 1
    
                    Dim xr As Double = ar.Array(j)
                    Dim xi As Double = ai.Array(j)
    
                    For r As Integer = n_radix To n - 1 Step n_radix
    
                        Dim wr0 As Double = Math.Cos(theta * m * r)
                        Dim wi0 As Double = Math.Sin(theta * m * r)
                        xr += (wr0 * ar.Array(r + j) - wi0 * ai.Array(r + j))
                        xi += (wr0 * ai.Array(r + j) + wi0 * ar.Array(r + j))
    
                    Next r
    
    
                    Dim wr As Double = Math.Cos(theta * m * j)
                    Dim wi As Double = Math.Sin(theta * m * j)
                    tmpr.Array(m * n_radix + j) = xr * wr - xi * wi
                    tmpi.Array(m * n_radix + j) = xi * wr + xr * wi
    
                Next m
    
            Next j
    
            For r As Integer = 0 To n - 1 Step n_radix
    
                fft(n_radix, theta * radix, New ArraySegment(Of Double)(tmpr.Array, tmpr.Offset + r, tmpr.Count - r), New ArraySegment(Of Double)(tmpi.Array, tmpi.Offset + r, tmpi.Count - r), ar, ai)
    
            Next r
    
    
    
            For j As Integer = 0 To n_radix - 1
    
                For m As Integer = 0 To radix - 1
    
                    ar.Array(radix * j + m) = tmpr.Array(n_radix * m + j)
                    ai.Array(radix * j + m) = tmpi.Array(n_radix * m + j)
    
                Next m
    
            Next j
    
    
        End Sub
    
    
    しかし、真っ白なデータしか出力されないのですが。。。。
    何が間違っていますでしょうか?
    
    
    
    
    
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91938  Re[16]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/12(Mon) 12:05:54)
    2019/08/12(Mon) 13:21:00 編集(投稿者)

    No91934 (えんえん さん) に返信
    > 何が間違っていますでしょうか?

    『ステップ実行』しましょう。

    ループ処理などを一行ずつ実行してみた上で、

      この場所では、この変数に
      こういう値がセットされるはずなのに、
      実際にはこんな値になってしまった
     」
    …という点を追跡できれば、どこの翻訳実装に問題があったことが明確になりますよね。


    > とりあえず、先に ArraySegmentを使った方法を試してみました。

    何か所か間違いがありますが、まずはここ。
     tmpr[m * n_radix + j] = xr * wr - xi * wi;

    No91934 のコードでは、上記を
    > tmpr.Array(m * n_radix + j) = xr * wr - xi * wi
    と翻訳してしまっていますので、ここが大きな間違いです。

    たとえば、
     Dim x() As Byte = New Byte(5) {11, 22, 33, 44, 55, 66}
     Dim y As New ArraySegment(Of Byte)(x)
     Dim z As New ArraySegment(Of Byte)(x, 2, 3)
    において、「y.Array」や「z.Array」は、配列 x への参照を意味します。
    ※ Span も似たようなものですが、Span はさらに各要素への参照も持ちます。

    なので、x(3) = 100 と代入すれば、z(1) も同様に 44 から 100 へと変化します。

    この時、それぞれの要素を列挙すれば
     x は {11, 22, 33, 100, 55, 66} 相当 (y.Array や z.Array も同様)
     y は {11, 22, 33, 100, 55, 66} 相当 (y.Offset は 0、y.Count は 6)
     z は {33, 100, 55} 相当 (z.Offset は 2、z.Count は 3)
    となります。
    Array / Offset / Count プロパティの 3 セットが、この構造体の肝です。
    ここまでは良いでしょうか。


    ArraySegment 構造体の場合、値の取得については
     MsgBox( z(i) )
    のように書けるのですが、問題は書き込みです。インデクサが ReadOnly なので、
     z(i) = newValue
    のようには書けません。(Span 構造体なら可能になるはず)

    そのため、オフセット指定の書き込みが必要な場合には、
     z.Array(z.Offset + i) = newValue
    のように、Array プロパティと Offset プロパティを併用することになります。
    No91934 のコードでは、この点が考慮されていないように見受けられます。


    =====

    それと、むやみに ByRef を使わないでください。
    今回は出力引数が存在しないため、ByRef の出番は一切ありません。

    先にも述べましたが、出力引数が必要な場合以外は、値渡しで実装するべきです。



    Sub Main()
      Dim x() As Byte = New Byte(3) {&H11, &H22, &HAB, &HCD}
      MsgBox(BitConverter.ToString(x))

      'AsSegment については No91917 を参照
      Test(x.AsSegment())
      MsgBox(BitConverter.ToString(x))

      Test(x.AsSegment(2, 2))
      MsgBox(BitConverter.ToString(x))
    End Sub

    ' a(0) と a(1) の中身を入れ替える処理
    ' この時、引数 ArraySegment 構造体を ByRef にする必要は無い!
    Sub Test(Of T)(ByVal a As ArraySegment(Of T))
      Dim swap() As T = {a(0), a(1)}
      a.Array(a.Offset + 1) = swap(0)
      a.Array(a.Offset + 0) = swap(1)
    End Sub


    ※ 先の No91917 ですが、最後の End Function が誤って End Sub になっていました。
     恐れ入りますが、 End Function に読み替えておいてください。


    > Public Sub one_D_FFT(ByRef xr#(), ByRef xi#())
    > Private Sub fft(ByVal n%, ByVal theta#, ByRef ar As ArraySegment(Of Double), ByRef ai As ArraySegment(Of Double), ByRef tmpr As ArraySegment(Of Double), ByRef tmpi As ArraySegment(Of Double))

    これらについて、メソッド名を分ける必要は無いと思います。オーバーロードで十分ではないでしょうか。
     Public Sub Fft(xr#(), xi#())
     Private Sub Fft(n%, theta#, ar As ArraySegment(Of Double), ar As ArraySegment(Of Double), tmpr As ArraySegment(Of Double), tmpi As ArraySegment(Of Double))


    メソッド名を分けるにしても、両者でメソッド名の大文字小文字の使い分けが不揃いな点が気にかかります。
    .NET Framework においては一般的に、
      ・クラス名やメソッド名は PascalCase 構文の大文字小文字表記とする。
      ・変数や引数は、camelCase 構文の大文字小文字表記とする。
    というのが一般的ですので、この点を意識したコーディングにされることをお奨めします。
    https://docs.microsoft.com/ja-jp/dotnet/standard/design-guidelines/naming-guidelines
    http://objectclub.jp/community/codingstandard/CodingStdVB.doc
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91939  Re[17]: C++からVBへの変換
□投稿者/ えんえん -(2019/08/12(Mon) 14:12:33)
    ありがとうございます。
    
    以下のようにしてみましたが
    やはりうまくいきませんでした。
    
    
        Public Sub one_D_FFT(ByRef xr#(), ByRef xi#())
    
    
            Dim n As Integer = xr.GetLength(0) - 1
    
            Dim theta = 2 * Math.PI / n
    
            Dim xr2 As New ArraySegment(Of Double)(xr), xi2 As New ArraySegment(Of Double)(xi)
    
            Dim tmpr(n) As Double, tmpi(n) As Double
            Dim tmpr2 As New ArraySegment(Of Double)(tmpr), tmpi2 As New ArraySegment(Of Double)(tmpi)
    
            Call fft(n, theta, xr2, xi2, tmpr2, tmpi2)
    
    
        End Sub
    
    
    
    
        ' Private Sub fft(ByVal n%, ByVal theta#, ByRef ar As ArraySegment(Of Double), ByRef ai As ArraySegment(Of Double), ByRef tmpr As ArraySegment(Of Double), ByRef tmpi As ArraySegment(Of Double))
        Private Sub fft(ByVal n%, ByVal theta#, ByVal ar As ArraySegment(Of Double), ByVal ai As ArraySegment(Of Double), ByVal tmpr As ArraySegment(Of Double), ByVal tmpi As ArraySegment(Of Double))
    
            If n <= 1 Then Exit Sub
    
            Dim radix As Integer = 2
            Do While radix * radix <= n
                If n Mod radix = 0 Then Exit Do
                radix += 1
            Loop
    
            If n Mod radix <> 0 Then radix = n
    
            Dim n_radix As Integer = n \ radix
    
            For j As Integer = 0 To n_radix - 1
    
                For m As Integer = 0 To radix - 1
    
                    Dim xr As Double = ar.Array(j)
                    Dim xi As Double = ai.Array(j)
    
                    For r As Integer = n_radix To n - 1 Step n_radix
    
                        Dim wr0 As Double = Math.Cos(theta * m * r)
                        Dim wi0 As Double = Math.Sin(theta * m * r)
                        xr += wr0 * ar.Array(r + j) - wi0 * ai.Array(r + j)
                        xi += wr0 * ai.Array(r + j) + wi0 * ar.Array(r + j)
    
                    Next r
    
    
                    Dim wr As Double = Math.Cos(theta * m * j)
                    Dim wi As Double = Math.Sin(theta * m * j)
                    tmpr.Array(tmpr.Offset + m * n_radix + j) = xr * wr - xi * wi
                    tmpi.Array(tmpi.Offset + m * n_radix + j) = xi * wr + xr * wi
    
                Next m
    
            Next j
    
            For r As Integer = 0 To n - 1 Step n_radix
    
                fft(n_radix, theta * radix, New ArraySegment(Of Double)(tmpr.Array, tmpr.Offset + r, tmpr.Count - r), New ArraySegment(Of Double)(tmpi.Array, tmpi.Offset + r, tmpi.Count - r), ar, ai)
    
            Next r
    
    
    
            For j As Integer = 0 To n_radix - 1
    
                For m As Integer = 0 To radix - 1
    
                    ar.Array(ar.Offset + radix * j + m) = tmpr.Array(n_radix * m + j)
                    ai.Array(ai.Offset + radix * j + m) = tmpi.Array(n_radix * m + j)
    
                Next m
    
            Next j
    
    
        End Sub
    
    
    
    
    > において、「y.Array」や「z.Array」は、配列 x への参照を意味します。
    
    > なので、x(3) = 100 と代入すれば、z(1) も同様に 44 から 100 へと変化します。
    
    「y.Array」や「z.Array」を書き換えた時
    元の配列xも同時に変化してくれないといけないのではないのでしょうか?
    元の配列xは変化しない方が良いという意味ですか?
    
    
    > それと、むやみに ByRef を使わないでください。
    > 今回は出力引数が存在しないため、ByRef の出番は一切ありません。
    
    
    fftを再帰的に呼び出しているわけですが、
    この場合、配列を書き換えて元のサブルーチンに返しているわけなので、
    参照型である必要があるのではないでしょうか?
    もっとも配列の場合、ByValを指定したところで、ByRef扱いになると思いますが
    間違っていますか?
    
    もし、出力引数がなければ、
    再帰処理の意味がなくなってしまうと思うのですが・・・
    
    
    
    どうやれば良いか分からないので、
    できれば、最終回答をお教えいただけないでしょうか?
    恐らく、こうやって何度もやりとりするよりも
    効率的だと思うのですが・・・
    
    一度、回答をいただけるとステップ実行しながら
    自分の間違いに気づけると思います
    
    
    
    
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91940  Re[18]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/12(Mon) 16:25:23)
    No91939 (えんえん さん) に返信
    No91939 (えんえん さん) に返信
    > 以下のようにしてみましたが
    > やはりうまくいきませんでした。

    同じ移植ミスを、他の行でも繰り返していますよ。

    Dim z As ArraySegment(Of T) における、
    z(0) と z.Array(0) の違いをもう一度見直してみましょう。


    >> において、「y.Array」や「z.Array」は、配列 x への参照を意味します。
    >> なので、x(3) = 100 と代入すれば、z(1) も同様に 44 から 100 へと変化します。
    > 「y.Array」や「z.Array」を書き換えた時
    > 元の配列xも同時に変化してくれないといけないのではないのでしょうか?

    はい。ご認識の通り、連動して変化します。
    そして先のそれは「変化することを理解していただくための説明コード」として記載したものです。


    No91938 の説明コードにおいて、読み取り専用の z(1) が x(3) と同じ物であり、
    それが z.Array(z.Offset + 1) を通じて書き換えられることを理解できていれば、
    >>> Dim xr As Double = ar.Array(j)

    >>> xr += (wr0 * ar.Array(r + j) - wi0 * ai.Array(r + j))

    >>> tmpi.Array(m * n_radix + j) = xi * wr + xr * wi

    >>> ai.Array(radix * j + m) = tmpi.Array(n_radix * m + j)
    といったミスをおこさずに済んだかと思います。


    あるいはこの移植ミスが理解不足によるものでもなく、
    単なるうっかりミスだったのであれば、「ステップ実行」して
    配列の内容を確認しながら動作チェックしていれば、
    その間違いに気づけたかもしれません。


    いずれにせよ、毎回、Offset を考慮したコードを書くのは移植ミスを引き起こしやすいので、
    元の C/C++ コードに近い記述にできるよう、何らかのヘルパーメソッドを
    設けることをおすすめしておきます。 No91917 のような拡張メソッドのように。


    > 元の配列xは変化しない方が良いという意味ですか?

    変化させる必要があるからこそ、ArraySegment の利用を提案した次第です。
    変化しないと再帰処理させられないという点は、 No91913 の冒頭でも述べていますね。


    ArraySegment を使わない場合は、御自身で書かれた r_st% のように、
    Offset に相当する引数をそれぞれの配列に対して用意する案が使えます。

    配列が 4 つあるので、本来であれば管理すべき添字も 4 つ分必要ですが、
    今回のケースでは tmp 版か否かで 2 系統あれば十分かと思います。
    (複素数の虚数部と実数部は同じ添字管理で済むため)


    > fftを再帰的に呼び出しているわけですが、
    > この場合、配列を書き換えて元のサブルーチンに返しているわけなので、
    > 参照型である必要があるのではないでしょうか?

    「『参照型』と『値型』の違い」の話と、
    「『参照渡し(ByRef)』と『値渡し(ByVal)』違い」の話が
    まだごっちゃになっているように見えます。


    > もっとも配列の場合、ByValを指定したところで、ByRef扱いになると思いますが
    > 間違っていますか?

    間違っています。


    今回の『void fft(int n, double theta, double ar[], double ai[], double tmpr[], double tmpi[])』において、
    配列部は double* 型のポインタと認識されますが、
     theta = 新しいdouble値;
     ar = 新しいdouble配列を指すポインタ;
     ai = 新しいdouble配列を指すポインタ;
     tmpr = 新しいdouble配列を指すポインタ;
     tmpi = 新しいdouble配列を指すポインタ;
    という処理は一切出てきません。

    あるのは、
     tmpr[何某] = 新しいdouble値;
     tmpi[何某] = 新しいdouble値;
     ar[何某] = 新しいdouble値;
     ai[何某] = 新しいdouble値;
    だけですよね。つまり、これらの引数は「出力引数」ではありません。


    同様に、今回記載された No91939 においても、
    仮引数に対して、新しい配列や ArraySegment を割り当てている個所はどこにもないですよね。
    実引数に対して、新しい配列や ArraySegment を割り当てている個所ならばありますけれども。
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91942  Re[18]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/12(Mon) 17:33:28)
    No91939 (えんえん さん) に返信
    > できれば、最終回答をお教えいただけないでしょうか?
    > 恐らく、こうやって何度もやりとりするよりも
    > 効率的だと思うのですが・・・

    申し訳ありませんが、現状は言語文法的な側面からしか回答できません。

    自分は高速フーリエ変換について正確に理解しているわけではないため、
    「作成依頼」に近い「質問」をされても、デバッグすることができないためです。


    実引数としてどういう値を入れた時に、なんという結果が返されるのか示す、
    ブラックボックステストのための情報があるわけでも無いですし。



    > もし、出力引数がなければ、
    > 再帰処理の意味がなくなってしまうと思うのですが・・・

    今回は ByVal で十分でしょう。

    改めて、 No91906 の最後の個所にあるコードで説明してみます。
    今回は意図的に ByVal を付けておきます。

      Sub Test4_Modify(ByVal a As ArraySegment(Of Double))
        a.Array(a.Offset + 1) *= 10
      End Sub

    このコードは「ByVal a As ArraySegment(Of T)」という宣言になっていますが、
    呼び出し元の値は、きちんと 10 倍になっています。


    ・ArraySegment(Of T) 構造体は値型。

    ・T が値型であれ参照型であれ、配列 T() は列は常に「参照型」。

    ・a.Array プロパティが返す型は As T() なので「参照型」。

    ・a.Array プロパティは ReadOnly であり、書き換えられない。
     たとえば「a.Array = Nothing」などと書くことはできない。

    ・a.Array プロパティから返される「一次元配列」は、
     ReadOnly というわけではないので、その要素を書き換えることができる。
     たとえば「a.Array(0) = Nothing」や「a(1) *= 10」と書いても良い。



    ==== 入力引数の例 <In> === ※いずれも ByVal で書いている。

     Sub Method1(ByVal x() As Integer)
       x(0) = 100 ' 呼び出し元の実引数では、配列の先頭要素が 100 に替わる。ただし、配列そのものが指しかわるわけでは無い。
     End Sub

     Sub Method2(ByVal lbl As Label)
       lbl.Text = CStr(Now) ' 呼び出し元で指定した Label のテキストが変化する。ただし、Label 型変数が別のラベルを指し示すわけでは無い。
     End Sub

     Sub Method3(ByVal pt As Point)
       Console.WriteLine("{0}, {1}", pt.X, pt.Y)
     End Sub


    ==== 出力引数の例 <Out> === ※いずれも ByRef で書いている。

     Sub Method4(ByRef x() As Integer)
       x = New Integer() { 0, 1, 2, 3 } ' 呼び出し元が渡した変数の内容は、新しい配列の参照へと差し替わる。
     End Sub

     Sub Method5(ByRef f As Form)
       f = New Form2() ' 呼び出し元が渡した変数の内容は、Form2 への参照へと書き換わる。
     End Sub

     Sub Method6(ByRef i As Integer)
       i = 12345 ' 呼び出し元が渡した変数の内容は、12345 という値に書き換わる。
     End Sub

     Sub Method7(ByRef pt As Point)
       pt = New Point(-1, 1) ' 呼び出し元が渡した変数の内容は、座標 (-1, 1) という値に置き換わる。
     End Sub


    ==== 入出力引数の例 <In, Out> === ※いずれも ByRef でなければならない。

     Sub Method8(ByRef x As Integer)
       x += 1
     End Sub

     Sub Method9(ByRef pt As Point)
       pt.Offset(-1, 1)
     End Sub

     Function Method10(ByVal x As Point) As Point
       pt.Offset(-1, 1)
       Return pt
     End Sub
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91941  Re[18]: C++からVBへの変換
□投稿者/ 774RR -(2019/08/12(Mon) 16:56:43)
    > できれば、最終回答をお教えいただけないでしょうか?
    それはあなただけに都合のいい話ですよね

    「正解をさっさと伝えるなんて指導者の怠慢さ」
    「自分で見つけた答えなら一生忘れない」
    from あおあし

    自分で理解することを頑張ってみて、それでも理解できなきゃ
    この業界が自分向けでない
    ってことでリタイアするもアリでしょ
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91946  Re[17]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/13(Tue) 01:00:13)
    No91938 (魔界の仮面弁士) に追記
    >  Dim x() As Byte = New Byte(5) {11, 22, 33, 44, 55, 66}
    >  Dim y As New ArraySegment(Of Byte)(x)
    >  Dim z As New ArraySegment(Of Byte)(x, 2, 3)
    > において、「y.Array」や「z.Array」は、配列 x への参照を意味します。
    > なので、x(3) = 100 と代入すれば、z(1) も同様に 44 から 100 へと変化します。

    補足説明。

    System.ArraySegment(Of T) は、.NET Framework 2.0 以上で使用可能な、比較的歴史の長い型ですが、
    「 z(1) 」のようにインデクサで参照するためには、.NET Framework 4.5 以上が必要となります。

    .NET Framework 4 以下の場合、LINQ 操作にさえ対応していないのでご注意ください。




    No91942 (魔界の仮面弁士) に追記
    >> できれば、最終回答をお教えいただけないでしょうか?
    > 申し訳ありませんが、現状は言語文法的な側面からしか回答できません。


    ということで、文法的に変換しただけで、コンパイルすらしていないコードですが、
    一応、当方で翻訳してみたものを掲載してみます。

    C/C++ はそもそも専門外ですし、FFT の理論も全く理解しておらず、おまけに
    どんな値を渡せばよいのか、そしてどういう結果になるべきかというテスト要件すら不明なので、
    およそ「最終回答」と呼ぶには程遠いコードではありますが、一応参考までに。



    'void fft(int n, double theta, double ar[], double ai[], double tmpr[], double tmpi[])
    '{
    Private Sub fft(ByVal n%, ByVal theta#, ByVal ar As ArraySegment(Of Double), ByVal ai As ArraySegment(Of Double), ByVal tmpr As ArraySegment(Of Double), ByVal tmpi As ArraySegment(Of Double))

      'if (n <= 1) return;
      If n <= 1 Then Exit Sub

      '/* ---- factorization ---- */
      'for (radix = 2; radix * radix <= n; radix++) {
      '  if (n % radix == 0) break;
      '}
      Dim radix As Integer = 2
      Do While radix * radix <= n
        If n Mod radix = 0 Then Exit Do
        radix += 1
      Loop

      'if (n % radix != 0) radix = n;
      'n_radix = n / radix;
      If n Mod radix <> 0 Then radix = n
      Dim n_radix As Integer = n \ radix

      '/* ---- butterflies ---- */
      'for (j = 0; j < n_radix; j++) {
      '  for (m = 0; m < radix; m++) {
      For j As Integer = 0 To n_radix - 1
        For m As Integer = 0 To radix - 1

          'xr = ar[j];
          'xi = ai[j];
          '==> ここから修正案の新コード
          Dim xr As Double = ar(j)
          Dim xi As Double = ai(j)
          '=== ここから No91939 の旧コード
          'Dim xr As Double = ar.Array(j)
          'Dim xi As Double = ai.Array(j)
          '<==


          'for (r = n_radix; r < n; r += n_radix) {
          For r As Integer = n_radix To n - 1 Step n_radix

            'wr = cos(theta * m * r);
            'wi = sin(theta * m * r);
            Dim wr0 As Double = Math.Cos(theta * m * r)
            Dim wi0 As Double = Math.Sin(theta * m * r)

            'xr += wr * ar[r + j] - wi * ai[r + j];
            'xi += wr * ai[r + j] + wi * ar[r + j];
            '==> ここから修正案の新コード
            xr += wr0 * ar(r + j) - wi0 * ai(r + j)
            xi += wr0 * ai(r + j) + wi0 * ar(r + j)
            '=== ここから No91939 の旧コード
            xr += wr0 * ar.Array(r + j) - wi0 * ai.Array(r + j)
            xi += wr0 * ai.Array(r + j) + wi0 * ar.Array(r + j)
            '<==

          '}
          Next r

          'wr = cos(theta * m * j);
          'wi = sin(theta * m * j);
          Dim wr As Double = Math.Cos(theta * m * j)
          Dim wi As Double = Math.Sin(theta * m * j)

          'tmpr[m * n_radix + j] = xr * wr - xi * wi;
          'tmpi[m * n_radix + j] = xi * wr + xr * wi;
          tmpr.Array(tmpr.Offset + m * n_radix + j) = xr * wr - xi * wi
          tmpi.Array(tmpi.Offset + m * n_radix + j) = xi * wr + xr * wi

        '}
        Next m

      '}
      Next j


      'for (r = 0; r < n; r += n_radix) {
      '  fft(n_radix, theta * radix, &tmpr[r], &tmpi[r], ar, ai);
      '}
      For r As Integer = 0 To n - 1 Step n_radix
        '==> ここから修正案の新コード (要 No91917 の拡張メソッド)
        fft(n_radix, theta * radix, tmpr.AsSegment(r), tmpi.AsSegment(r), ar, ai)
        '=== ここから No91939 の旧コード
        fft(n_radix, theta * radix, New ArraySegment(Of Double)(tmpr.Array, tmpr.Offset + r, tmpr.Count - r), New ArraySegment(Of Double)(tmpi.Array, tmpi.Offset + r, tmpi.Count - r), ar, ai)
        '<==
      Next r

      'for (j = 0; j < n_radix; j++) {
      '  for (m = 0; m < radix; m++) {
      '    ar[radix * j + m] = tmpr[n_radix * m + j];
      '    ai[radix * j + m] = tmpi[n_radix * m + j];
      '  }
      '}
      For j As Integer = 0 To n_radix - 1
        For m As Integer = 0 To radix - 1
          '==> ここから修正案の新コード (要 No91917 の拡張メソッド)
          ar.SetValue( radix * j + m, tmpr(n_radix * m + j) )
          ai.SetValue( radix * j + m, tmpi(n_radix * m + j) )
          '=== ここから No91939 の旧コード
          ar.Array(ar.Offset + radix * j + m) = tmpr.Array(n_radix * m + j)
          ai.Array(ai.Offset + radix * j + m) = tmpi.Array(n_radix * m + j)
          '<==
        Next m
      Next j

    '}
    End Sub
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91944  Re[14]: C++からVBへの変換
□投稿者/ 魔界の仮面弁士 -(2019/08/12(Mon) 22:51:04)
    No91932 (774RR さん) に返信
    > FFT なんぞテキトーに探せばいくらでもライブラリが転がっているような気のせいがする。

    下記によれば、Math.NET Numerics で処理できるっぽいです。
    https://tomosoft.jp/design/?p=9127
    https://www.nuget.org/packages/MathNet.Numerics/

    MathNet.Numerics.IntegralTransforms 名前空間の Fourier クラスが、
     Public Shared Sub Forward(ByVal samples() As System.Numerics.Complex)
     Public Shared Sub Forward(ByVal samples() As System.Numerics.Complex, ByVal options As FourierOptions)
    Public Shared Sub Forward(ByVal real() As Double, ByVal imaginary() As Double, Optional ByVal options As FourierOptions = FourierOptions.Default)
    などのメソッドを持っていました。


    Double 配列から、虚数データ無しの複素数構造体配列に変換する場合はこんな感じ。
     Dim rawData() As Double = 元データ
     Dim samples() As Complex = rawData.Select(Function(d) New Complex(d, 0#)).ToArray()


    options 引数はフーリエ変換規則を示す物らしいですが…今回の目的に合致するものがあるかは分かりませんでした。

    Dim options As FourierOptions
    options = FourierOptions.Default '0: 普遍的; 対称スケーリングおよび共通指数(Maple で使用)
    options = FourierOptions.AsymmetricScaling '2: 逆方向に 1/N だけスケーリング; 順方向のスケーリングなし
    options = FourierOptions.Matlab '2: 逆方向に 1/N だけスケーリング; 順方向のスケーリングなし(Mathlab で使用) [AsymmetricScaling と同じ]
    options = FourierOptions.NoScaling '4: 何もスケーリングしない (順方向変換でも逆方向変換でもない)
    options = FourierOptions.InverseExponent '1: 逆被積分指数 (順方向:正符号、逆方向:負符号)
    options = FourierOptions.NumericalRecipes '5: 逆被積分指数; 何もスケーリングしない(すべての数値レシピベースの実装で使用)[= InverseExponent Or NoScaling]
記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■91947  Re[15]: C++からVBへの変換
□投稿者/ えんえん -(2019/08/13(Tue) 11:01:38)
    ありがとうございます。

    うまくいきました
    ばっちりでした!!!!!!

    今から、自分のコードで何が間違っていたか確認したいと思います。

    ちなみに

    > 下記によれば、Math.NET Numerics で処理できるっぽいです。


    Math.NET Numerics などのライブラリでFFTが実装されるのは知っていますし
    使ったこともあります。
    ただ、こうしたライブラリは基数が2のべき乗にしか対応していないのです。

    任意の基数に対応したFFTのライブラリってなぜか見つからないのです。


記事No.91899 のレス /過去ログ158より / 関連記事表示
削除チェック/

■98783  Re[2]: csvファイルを印刷したい
□投稿者/ くま -(2021/12/23(Thu) 01:51:39)
    2021/12/23(Thu) 02:03:18 編集(投稿者)


    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    Dim path As String = "D:\TEST\TestCSV.CSV" '対象ファイル
    Dim lines As List(Of String) = New List(Of String)
    Dim line As String
    Dim items() As String
    'ファイルをutf-8コードとして開く
    Using sr As New System.IO.StreamReader(path, System.Text.Encoding.GetEncoding("utf-8"))
    While sr.Peek() > -1
    line = sr.ReadLine()
    If line.Length > 0 Then
    items = line.Split(",")
    line = ""
    For Each item As String In items
    line &= "<td style=""white-space: nowrap;padding:0 5px;"">" & item & "</td>"
    Next
    line = "<tr>" & line & "</tr>"
    lines.Add(line)
    End If
    End While
    End Using

    Dim sauce As String = ""
    sauce = "<table border=""0"" cellspacing=""0"" cellpadding=""0"" bordercolor=""#ffffff"">" & Strings.Join(lines.ToArray) & "</table>"
    sauce = "<html><body style=""margin:0;padding:0;"">" & sauce & "</body></html>"

    Dim webBrowserForPrinting As New WebBrowser()
    webBrowserForPrinting.Parent = Me
    webBrowserForPrinting.Visible = False
    AddHandler webBrowserForPrinting.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PrintDocument)
    webBrowserForPrinting.DocumentText = sauce

    End Sub
    Private Sub PrintDocument(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
    Dim webBrowserForPrinting As WebBrowser = CType(sender, WebBrowser)
    webBrowserForPrinting.ShowPrintPreviewDialog()
    End Sub
記事No.98776 のレス /過去ログ171より / 関連記事表示
削除チェック/

<前の20件

<< 0 | 1 >>

パスワード/

- Child Tree -