3

ツールを使用して約 90 以上の Fortran ファイルを C ファイルに変換しましたが、変換が適切かどうかを検証する必要があります。

翻訳によって機能が確実に保持されるようにするための最善の方法について、いくつかのアイデアを教えていただけますか?

4

3 に答える 3

3

これらの fortran 関数を実行する検証テストが必要です。次に、これらのテストを c コードに対して実行します。

単体テスト技術/方法論を使用できます。実際、変換が正しいことを他にどのように証明するかわかりません。

多くの単体テスト方法論では、コードと同じ言語でテストを記述しますが、この場合、1 つの言語と 1 つのコード ベースを選択して、両方の機能セットを実行することを強くお勧めします。また、純粋な単体テストを作成しようとすることを心配する必要はありません。むしろ、Fortran コードが処理するはずだったすべての使用法をカバーする手法を使用してください。

于 2012-07-04T11:28:28.390 に答える
2

単体テストを使用します。

最初に Fortran コードで単体テストを作成し、それらがすべて正しく実行されるかどうかを確認してから、それらを C で書き直して実行します。

このアプローチの問題点は、単体テストも書き直す必要があることです。これは通常、コードをリファクタリングするときは行いません (API の変更を除く)。これは、実際のコードに加えて、移植された単体テスト コードもデバッグすることになる可能性があることを意味します。

したがって、最小限のロジックを含むテスト コードを記述し、関数の結果のみをファイルに書き込む方がよい場合があります。次に、この最小限のテスト コードを C で書き直して、同じファイルを生成し、ファイルを比較します。

于 2012-07-04T11:29:15.663 に答える
1

「同様の」タスクに対して私が行ったことは次のとおりです(fortran 90とfortran 90 + OpenACC GPUアクセラレーションコードの比較):

  1. 各 Fortran モジュールの出力を分析します。
  2. これらの出力配列を .dat ファイルに書き込みます。
  3. .dat ファイルを参照フォルダーにコピーします。
  4. 変換されたモジュールの出力をファイル (CSV またはバイナリ) に書き込みます。便宜上、同じファイル名を使用してください。
  5. 2 つのバージョンを比較する Python スクリプトを作成します。

Fortran で次のような便利な関数を使用しました (1D、2D の場合と同様):

subroutine write3DToFile(path, array, n1, n2, n3)
   use pp_vardef
   use pp_service, only: find_new_mt
   implicit none

   !input arguments
   real(kind = r_size), intent(in) :: array(n1,n2,n3)
   character(len=*), intent(in) :: path
   integer(4) :: n1
   integer(4) :: n2
   integer(4) :: n3

   !temporary
   integer(4) :: imt

   call find_new_mt(imt)

   open(imt, file = path, form = 'unformatted', status = 'replace')
   write(imt) array
   close(imt)
 end subroutine write3DToFile

Python では、次のスクリプトを使用してバイナリ Fortran データを読み取り、比較しました。注: C に変換したいので、Fortran の代わりに C によって生成されたデータを読み取れるように変更する必要があります。

from optparse import OptionParser
import struct
import sys
import math

def unpackNextRecord(file, readEndianFormat, numOfBytesPerValue):
    header = file.read(4)
    if (len(header) != 4):
        #we have reached the end of the file
        return None

    headerFormat = '%si' %(readEndianFormat)
    headerUnpacked = struct.unpack(headerFormat, header)
    recordByteLength = headerUnpacked[0]
    if (recordByteLength % numOfBytesPerValue != 0):
        raise Exception, "Odd record length."
        return None
    recordLength = recordByteLength / numOfBytesPerValue

    data = file.read(recordByteLength)
    if (len(data) != recordByteLength):
        raise Exception, "Could not read %i bytes as expected. Only %i bytes read." %(recordByteLength, len(data))
        return None

    trailer = file.read(4)
    if (len(trailer) != 4):
        raise Exception, "Could not read trailer."
        return None
    trailerUnpacked = struct.unpack(headerFormat, trailer)
    redundantRecordLength = trailerUnpacked[0]
    if (recordByteLength != redundantRecordLength):
        raise Exception, "Header and trailer do not match."
        return None

    dataFormat = '%s%i%s' %(readEndianFormat, recordLength, typeSpecifier)
    return struct.unpack(dataFormat, data)

def rootMeanSquareDeviation(tup, tupRef):
    err = 0.0
    i = 0
    for val in tup:
        err = err + (val - tupRef[i])**2
        i = i + 1
    return math.sqrt(err)

##################### MAIN ##############################
#get all program arguments
parser = OptionParser()
parser.add_option("-f", "--file", dest="inFile",
                  help="read from FILE", metavar="FILE", default="in.dat")
parser.add_option("--reference", dest="refFile",
                  help="reference FILE", metavar="FILE", default="ref.dat")
parser.add_option("-b", "--bytesPerValue", dest="bytes", default="4")
parser.add_option("-r", "--readEndian", dest="readEndian", default="big")
parser.add_option("-v", action="store_true", dest="verbose")

(options, args) = parser.parse_args()

numOfBytesPerValue = int(options.bytes)
if (numOfBytesPerValue != 4 and numOfBytesPerValue != 8):
    print "Unsupported number of bytes per value specified."
    sys.exit()
typeSpecifier = 'f'
if (numOfBytesPerValue == 8):
    typeSpecifier = 'd'

readEndianFormat = '>'
if (options.readEndian == "little"):
    readEndianFormat = '<'

inFile = None
refFile = None
try: 
    #prepare files
    inFile = open(str(options.inFile),'r')
    refFile = open(str(options.refFile),'r')

    i = 0
    while True:
        passedStr = "pass"
        i = i + 1
        unpackedRef = None
        try: 
            unpackedRef = unpackNextRecord(refFile, readEndianFormat, numOfBytesPerValue)
        except(Exception), e:
            print "Error reading record %i from %s: %s" %(i, str(options.refFile), e)
            sys.exit()

        if (unpackedRef == None):
            break;

        unpacked = None
        try:
            unpacked = unpackNextRecord(inFile, readEndianFormat, numOfBytesPerValue)
        except(Exception), e:
            print "Error reading record %i from %s: %s" %(i, str(options.inFile), e)
            sys.exit()

        if (unpacked == None):
            print "Error in %s: Record expected, could not load record it" %(str(options.inFile))
            sys.exit()

        if (len(unpacked) != len(unpackedRef)):
            print "Error in %s: Record %i does not have same length as reference" %(str(options.inFile), i)
            sys.exit()

        #analyse unpacked data
        err = rootMeanSquareDeviation(unpacked, unpackedRef)
        if (abs(err) > 1E-08):
            passedStr = "FAIL <-------"
        print "%s, record %i: Mean square error: %e; %s" %(options.inFile, i, err, passedStr)

        if (options.verbose):
            print unpacked

except(Exception), e:
    print "Error: %s" %(e)

finally:
    #cleanup
    if inFile != None:
        inFile.close()

    if refFile != None:
        refFile.close()
于 2012-07-09T06:28:40.117 に答える