2次元配列の定数ファイルをExcelで自動生成したい。


例えば、10×10の配列データとして、以下を定義するとします。
table99[10][10] = {
{0,0,0,0,0,0,0,0,0,0}
{0,1,2,3,4,5,6,7,8,9}
{0,2,4,6,8,10,12,14,16,18}
:
:
:
{0,9,18,27,36,45,54,63.72.81}
}

これを定数ファイルとして、Excelから自動で出力したいと考えています。
10×10くらいなら、無理やりExcelで表作って、CSV保存して切った貼ったでもなんとかなるのですが
256×256のテーブルを10個作らないといけないことが分かり、しかも数値が一部見直しになる可能性もありってことで、ちょっと省力化できないかな、と考えています。

回答の条件
  • 1人1回まで
  • 登録:2015/08/25 00:50:54
  • 終了:2015/08/31 23:39:39
id:gm91

質問者から

GM912015/08/25 03:16:20

要求仕様をまとめると
1)要素数は256×256
2)各要素の中身は符号付浮動小数で記載。
3)できれば、10点×10点くらいをExcelに記入したら、256×256点のテーブルへ展開したい。
4)256点 という要素数は変動なし。簡易に変更できればなおよい。
5)256×256のテーブルはExcel上でみれなくてもOK。いきなりc言語用ファイルを吐いてもOK。
こんな感じです。
その他、不明点あれば追加します。

また、参考になるサイトの紹介などでもOKです。
何卒宜しくお願いします。

ベストアンサー

id:a-kuma3 No.4

a-kuma3回答回数4502ベストアンサー獲得回数18692015/08/25 10:19:59

ポイント300pt

3)できれば、10点×10点くらいをExcelに記入したら、256×256点のテーブルへ展開したい。

これがよく分からなかったので、以下のようにしました。

  • 質問にある例のような感じで 256×256 を埋める
  • データを作るサブルーチンと、データを保存するサブルーチンのふたつを用意

Const max = 256

'   256 × 256 の表を作成
Sub make_data()
    For r = 1 To max
        For c = 1 To max
            Cells(r, c) = (r - 1) * (c - 1)
        Next
    Next
End Sub



'   256 × 256 の表を配列の宣言形式でファイルに保存
Sub output_data()
    Filename = "D:\table99.h"
    Open Filename For Output As #1
    Print #1, "double table99["; max; "]["; max; "] = {"
    For r = 1 To max
        Print #1, "{";
        For c = 1 To max
            Print #1, Format(Cells(r, c), "0.#########");
            If c <> max Then
                Print #1, ",";
            Else
                Print #1, "},"
            End If
        Next
    Next
    Print #1, "};"
    Close #1
End Sub

256×256 の表は、10×10 の領域をコピーする、もしくは、ある範囲を決めてランダムな数字で埋める、とか、いろいろやり方はあるでしょうが、サブルーチン make_data のループの中身を書き換えれば良いかな、と。



追記です。

簡単にいうと、10×10(16×16とかでもOK)くらいの入力点の間を内挿して、256点×256点のテーブルを作りたいのです。
内挿する点は与えた点の直線補間でOK。
  ...
※贅沢を言えば、入力する点数は10×10~20×20くらいで対応できると嬉しいです。(出力は256^2で固定OK)


データを作るところを以下のようにしました。

Const from_max = 10
Const max = 256

Function calc_interpolation(r, c)
    mm = CDbl(max - 1)

    x = (c - 1) * (from_max - 1) / mm + 1
    y = (r - 1) * (from_max - 1) / mm + 1

    x0 = Application.RoundDown(x, 0)
    x1 = x0 + 1
    y0 = Application.RoundDown(y, 0)
    y1 = y0 + 1

    v00 = Cells(y0, x0).Value
    v10 = Cells(y0, x1).Value
    v01 = Cells(y1, x0).Value
    v11 = Cells(y1, x1).Value

    v = (x1 - x) * ((y1 - y) * v00 + (y - y0) * v01) + (x - x0) * ((y1 - y) * v10 + (y - y0) * v11)
    calc_interpolation = v

End Function

Sub make_data()
    Set to_sheet = Worksheets("Sheet2")
    For r = 1 To max
        For c = 1 To max
            to_sheet.Cells(r, c).Value = calc_interpolation(r, c)
        Next
    Next
End Sub

選択中のシートの左上10×10 の領域を、"Sheet2" の 256×256 の領域に書き出します。
先の回答のファイルへの書き出しと共有してるので、変数名が変な感じになってますが、対象の大きさは以下の定数で変更できます(A1 から始まるところと、行と列の大きさが等しいところは固定です)。

  • from_max:入力元の大きさ
  • max:出力先の大きさ

データの補間には、画像を拡大するときに使われる「双一次補間」というのを使いました。
http://imagingsolution.blog107.fc2.com/blog-entry-142.html

ちょっと遅いです。10秒近くかかると思います。
上手くやれば、もっと速くできると思いますが、そう何度も使うマクロではないと思うので :-)

他8件のコメントを見る
id:a-kuma3

度々、すみません。
X と Y のデータを取り違えてました。

    v00 = Cells(x0, y0).Value
    v10 = Cells(x1, y0).Value
    v01 = Cells(x0, y1).Value
    v11 = Cells(x1, y1).Value

の部分は、以下のようになっているのが正解です。

    v00 = Cells(y0, x0).Value
    v10 = Cells(y0, x1).Value
    v01 = Cells(y1, x0).Value
    v11 = Cells(y1, x1).Value

# 回答のコードも修正しました m(_ _)m


おまけ。
元の 10×10 の領域にランダムな値を埋めるサブルーチンです。下記では -50 ~ +50 の範囲の乱数を入れてます。

Sub make_data_random()
    vfirst = -50
    vrange = 100
    Randomize
    For r = 1 To from_max
        For c = 1 To from_max
            Cells(r, c).Value = vfirst + Rnd * vrange
        Next
    Next
End Sub

# うーん、テスト 大切だ

2015/08/26 10:42:26
id:gm91

ありがとうございます。
シート名は自分で直したので無問題よ。
ちなみにウチのpcだと待たされ感ゼロです。

2015/08/26 12:43:34

その他の回答(3件)

id:cdaotg No.1

cdaotg回答回数85ベストアンサー獲得回数212015/08/25 01:20:56

ポイント1pt

以下の手順ではどうでしょうか?

1. Excel上でテーブルを作成する。
2. テーブルをCSVで保存する。
3. CSVファイルを読み込み、C言語用のファイルを吐くプログラムを実行する。

3.用のプログラムだけ作成する必要がありますが、これは簡単に出来ると思います。

id:gm91

ありがとうございます
その方法でやろうとしていて、それを力づくでなく楽に処理できないか、という質問です。

2015/08/25 08:25:33
id:segavvy No.2

segavvy回答回数7ベストアンサー獲得回数32015/08/25 01:33:40

ポイント3pt

ちょっと手元にExcelがないので確実にできるかは自信がないのですが、Excelで256*256の表を作って"data.csv"というファイル名でCSV出力し、

float table[256][256] = {
#include "data.csv"
};

みたいな感じで書けば初期化できそうな気がします。

Cなら2次元配列でも256*256個の1次元配列として初期化できますので、256ごとの{}は不要です。ただし、csvファイルの各行の最後に","が必要なので、Excelで最後のセルに空白を入れるなどして、行末に","が入るようにしないとダメですね。

できなかったらゴメンなさい...

id:gm91

ありがとうございます。
質問の趣旨は
c言語への取り込み方ではなく
ファイルの生成方法、です。

2015/08/25 08:27:32
id:rsc96074 No.3

rsc回答回数4394ベストアンサー獲得回数4022015/08/25 08:05:04

ポイント50pt

 いきなりc言語用ファイルを吐いてもOKということで、こんな感じでどうでしょうか。(^_^;

Option Explicit

Sub mkTable()
    Dim i, j, m, n As Integer
    Dim s As String
    m = 256
    n = m
    s = "float table[" + Trim(Str(m)) + "][" + Trim(Str(n)) + "] = {" + vbCrLf
    For i = 0 To m - 1
        s = s + vbTab + "{"
        For j = 0 To n - 1
            If i < 10 And j < 10 Then
                s = s + Str(i * j) + ".0"
            Else
                s = s + Str(0) + ".0"
            End If
            If j < n - 1 Then s = s + ","
        Next j
        s = s + "}"
        If i < m - 1 Then s = s + ","
        s = s + vbCrLf
    Next i
    s = s + "};" + vbCrLf
    'Debug.Print s
    Open "output.txt" For Output As #1
        Print #1, s
    Close #1
End Sub

 10×10のデータから256×256のデータを予想するのをちょっとやってみました。(^_^;
 FORECASTのxの範囲用に258行目を使いました。(^_^;

Sub macroAll()
    Call mkTable1
    Call mkTable2
End Sub

'種データ
Sub mkTable1()
    Cells.Clear
    Dim i, j As Integer
    
    For i = 1 To 10
        For j = 1 To 10
            Cells(i, j) = (i - 1) * (j - 1)
        Next
    Next
    
    ' Forecast用
    Dim k As Integer
    For k = 1 To 10
        Cells(258, k).Value = k
    Next k
End Sub

' Forecastで予想してみる
Sub mkTable2()
    Dim i, j, k, m, n As Integer
    m = 256
    n = m
    For k = 11 To m
        For j = 1 To k - 1
            Cells(k, j).Value = calc1(k, j)
        Next j
        For i = 1 To k
            Cells(i, k).Value = calc2(i, k)
        Next i
    Next k
End Sub

Function calc1(i, j) As Double
    calc1 = WorksheetFunction.Forecast(i, Range(Cells(1, j), Cells(10, j)), Range(Cells(258, 1), Cells(258, 10)))
End Function

Function calc2(i, j) As Double
    calc2 = WorksheetFunction.Forecast(j, Range(Cells(i, 1), Cells(i, 10)), Range(Cells(258, 1), Cells(258, 10)))
End Function

※参考URL
http://dekiru.net/article/4566/

他1件のコメントを見る
id:rsc96074

 もしかして、10×10は自分でセルに入力しておいて、他の256×256を補間法で計算するってことですか。(?_?;

2015/08/25 18:23:50
id:gm91

そうです

2015/08/25 19:22:25
id:a-kuma3 No.4

a-kuma3回答回数4502ベストアンサー獲得回数18692015/08/25 10:19:59ここでベストアンサー

ポイント300pt

3)できれば、10点×10点くらいをExcelに記入したら、256×256点のテーブルへ展開したい。

これがよく分からなかったので、以下のようにしました。

  • 質問にある例のような感じで 256×256 を埋める
  • データを作るサブルーチンと、データを保存するサブルーチンのふたつを用意

Const max = 256

'   256 × 256 の表を作成
Sub make_data()
    For r = 1 To max
        For c = 1 To max
            Cells(r, c) = (r - 1) * (c - 1)
        Next
    Next
End Sub



'   256 × 256 の表を配列の宣言形式でファイルに保存
Sub output_data()
    Filename = "D:\table99.h"
    Open Filename For Output As #1
    Print #1, "double table99["; max; "]["; max; "] = {"
    For r = 1 To max
        Print #1, "{";
        For c = 1 To max
            Print #1, Format(Cells(r, c), "0.#########");
            If c <> max Then
                Print #1, ",";
            Else
                Print #1, "},"
            End If
        Next
    Next
    Print #1, "};"
    Close #1
End Sub

256×256 の表は、10×10 の領域をコピーする、もしくは、ある範囲を決めてランダムな数字で埋める、とか、いろいろやり方はあるでしょうが、サブルーチン make_data のループの中身を書き換えれば良いかな、と。



追記です。

簡単にいうと、10×10(16×16とかでもOK)くらいの入力点の間を内挿して、256点×256点のテーブルを作りたいのです。
内挿する点は与えた点の直線補間でOK。
  ...
※贅沢を言えば、入力する点数は10×10~20×20くらいで対応できると嬉しいです。(出力は256^2で固定OK)


データを作るところを以下のようにしました。

Const from_max = 10
Const max = 256

Function calc_interpolation(r, c)
    mm = CDbl(max - 1)

    x = (c - 1) * (from_max - 1) / mm + 1
    y = (r - 1) * (from_max - 1) / mm + 1

    x0 = Application.RoundDown(x, 0)
    x1 = x0 + 1
    y0 = Application.RoundDown(y, 0)
    y1 = y0 + 1

    v00 = Cells(y0, x0).Value
    v10 = Cells(y0, x1).Value
    v01 = Cells(y1, x0).Value
    v11 = Cells(y1, x1).Value

    v = (x1 - x) * ((y1 - y) * v00 + (y - y0) * v01) + (x - x0) * ((y1 - y) * v10 + (y - y0) * v11)
    calc_interpolation = v

End Function

Sub make_data()
    Set to_sheet = Worksheets("Sheet2")
    For r = 1 To max
        For c = 1 To max
            to_sheet.Cells(r, c).Value = calc_interpolation(r, c)
        Next
    Next
End Sub

選択中のシートの左上10×10 の領域を、"Sheet2" の 256×256 の領域に書き出します。
先の回答のファイルへの書き出しと共有してるので、変数名が変な感じになってますが、対象の大きさは以下の定数で変更できます(A1 から始まるところと、行と列の大きさが等しいところは固定です)。

  • from_max:入力元の大きさ
  • max:出力先の大きさ

データの補間には、画像を拡大するときに使われる「双一次補間」というのを使いました。
http://imagingsolution.blog107.fc2.com/blog-entry-142.html

ちょっと遅いです。10秒近くかかると思います。
上手くやれば、もっと速くできると思いますが、そう何度も使うマクロではないと思うので :-)

他8件のコメントを見る
id:a-kuma3

度々、すみません。
X と Y のデータを取り違えてました。

    v00 = Cells(x0, y0).Value
    v10 = Cells(x1, y0).Value
    v01 = Cells(x0, y1).Value
    v11 = Cells(x1, y1).Value

の部分は、以下のようになっているのが正解です。

    v00 = Cells(y0, x0).Value
    v10 = Cells(y0, x1).Value
    v01 = Cells(y1, x0).Value
    v11 = Cells(y1, x1).Value

# 回答のコードも修正しました m(_ _)m


おまけ。
元の 10×10 の領域にランダムな値を埋めるサブルーチンです。下記では -50 ~ +50 の範囲の乱数を入れてます。

Sub make_data_random()
    vfirst = -50
    vrange = 100
    Randomize
    For r = 1 To from_max
        For c = 1 To from_max
            Cells(r, c).Value = vfirst + Rnd * vrange
        Next
    Next
End Sub

# うーん、テスト 大切だ

2015/08/26 10:42:26
id:gm91

ありがとうございます。
シート名は自分で直したので無問題よ。
ちなみにウチのpcだと待たされ感ゼロです。

2015/08/26 12:43:34
id:gm91

質問者から

GM912015/08/25 14:52:56

ありがとうございます
試してみます

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません