市販品みたいな本格的ラジオキット

アナログ短波ラジオの仕組みが知りたくて中夏牌 ZX-623を作ったが、短波側がいまいちで15.0~15.5MHzが入る程度のおまけ程度仕様。短波ラジオとしては残念仕様。

今回は「本格的」とうたわれてる短波対応のラジオキットを組んでみた。

FM(76~108MHz)/AM(520~1700kHz)/SW2バンド(3~10MHz/10~22MHz)の4バンド構成で簡易な短波ラジオとして極めて市販品的。海外製品でよくあるFM80~108MHzでないところもポイントが高い。とっとと組み立てて調整。組立に1日、調整に2時間程度かかった。 市販品をキット化したもののようだから、組立キット用として設計されたものより複雑でキットとしてはかなり難しい部類に入る。チップ部品は実装されている(ICは自分で付ける)が下手にいじると飛ばすし、ジャンパの配線すら回路図が読めないと難しい。本来は工場の手慣れた工員が、調整ジグ類が完備されたところで組まれるものを、一般家庭の汎用工具と手練れの職人技無しに組み立てるのだから難しいのが当然といえば当然。工場の組み立てで1日もかけてたら日当5000円はくだらない。

上の写真は調整が完了してない状態。バーアンテナはもっと抜かれた状態、上側の短波用コイルはもっと入った状態になった。右下のFM用コイルは調整が完了して開いた状態になっている。

回路図は公開されていないので組立説明書に載せられているものを参考にする。買わない人向けには公開されていないから掲載はできないけれど、AM/SWのチューナーは次のような構成になっている。

・MW/SWの同調、局発回路は3組6個のコイル、トリマコンを持つ。
・MWの同調コイルはバーアンテナ、SWの同調コイルは角型のコイル。
・ポリバリコンはMWの同調、局発と共用。スライドスイッチで切り替える。
・SWの同調、局発コイルはそれぞれトリマコンとセット。

中夏牌のSW帯はポリバリコンのFM部を流用しているのでチューニング範囲が500kHz程度と狭くなっていたが、このキットはAM側を完全に切り替えるようになっているので7MHz/12MHzと広い範囲で同調できるようになっている。知ってしまうとどうということも無いが、回路を見てなるほどと思った。調整のしかたもちゃんと載っていて、手持ちのディップメータとアナログオシロとデジタル表示の短波ラジオで何度か調整しているとだんだんトラッキングが合うようになってきた。ただ短波用アンテナと称して4m程度のリード線が付いてくることからも推測できるが、完全に調整し切っても超高感度というわけでは無さそう。10年ほど前に買った市販の「手回し+ソーラー発電、ライト・携帯充電 (のあまり使い物にならない) 機能付きAM/FM/SWラジオ」の短波帯の受信感度はそれほど良くなくて似たような雰囲気だった。調整が完了した本機はそれより少し良い気がするが、バンドスプレッド方式のアナログ短波ラジオよりは良くない。

他の不思議ポイントとしては回し発電+ソーラーパネル+組み込みNiMH電池が電源で外部電源、乾電池は使用不可という謎仕様。イヤホンジャックも無し。基板の折り取る部分にはイヤホン、DCジャックのパターンがあるし、回路図にも載っているから上位機種では装備されているのだろう。国内メーカ品だとライト、サイレン機能なんかが付いてダイナモ部分がメインの教材になるんだけど、このキットはダイナモは組み込み済みであくまでラジオがメイン。あとバンド切り替えに関わるところに今ではレアパーツのスチコンが使われているところも不思議。

キットも市販品もラジオはDSP化が進んでいるが、ラジオキットでもアナログ回路でFM受信や短波受信ができるものはもともと少なくて、このキットも中夏牌も貴重なものだ。だれでも簡単に作れて再現性が良いのも結構だが、はんだ付けメインで生産ラインの体験学習や工場の手練れパート工員になる職業訓練をしたいのでなければ、 理由がわかった上で回路の構成と調整の仕方くらいは身につけたい。

広告

Seemile韓国語を卒業した。

一年ほどかけてSeemile韓国語という学習アプリをようやく終えた。

有料アプリで、韓国語の基礎文法やある程度の語彙を簡単なアニメーションと音声で教えてくれる。 アプリ自体の学習機能は少々退屈だったが、それよりも秀逸なのはYoutubeに上がっている無料のビデオ。講師の朴英蘭(박영란:パクヨンラン)さんがきれいな人で解説が上手なので続けて見られる。ビデオのボリュームも多くて他の教材が要らない。このブログで書いてる韓国語ネタはSeemileアプリとビデオで学んだ結果でもある。まだまだ単語を知らないのでこれから語彙を増やせるかどうか。

変な文字」を音読したいという弱い動機ではじめたが、現時点でもKPOPの発音をほぼ正確に歌うこともできるし、 楽しい韓国アニメを見ることもできるようになってきたし、北朝鮮の意味不明な放送もなんとなくわかるようになってきたしちょっと面白い。

Seemile中国語というのもあって韓国語版が終わったら着手しようかと思ってとりあえず有料版にしたが、こちらには日本語版の学習ビデオが無いのが残念。アプリ内のストーリーは韓国語版と同じなので内容の理解は難しくなさそう。ストーリーで出てくる日本人「田中瞳」が韓国語版では名だけで히토미(ヒトミ)なのに、中国語版で田中瞳が姓名の中国語読み「テンチョントン」になっていたのには驚いた。

日中韓の言語スペック比較。

漢字文化圏、日中韓の言語スペック比較。

・文法 – 細かいことは際限ない。
日本語 活用有り、助詞有り、敬語 中。文脈読み 要。
中国語 活用無し、助詞無し、敬語 少。
韓国語 活用有り、助詞有り、敬語 多。省略形 多。

・文字
日本語 ひらがな、カタカナ、日本漢字。
中国語 簡体字。
韓国語 ハングル。

・漢字 – よく使う漢字。
日本語 字数 約3000字。複数読み有り。
中国語 字数 約3500字。複数読み少。
韓国語 字数 0字、教育用は1800字。複数読み少。

・発音
日本語 母音5音、声調無し、長音有り。
中国語 基本母音6音、 声調(四声)有り。
韓国語 基本母音6音 、声調無し(濃音有り)、終声子音有り。

・難易度
日本語 日本人は日本語が一番難しいと思っている。
中国語 中国人は中国語が一番難しいと思っている。
韓国語 韓国人はハングルが一番優れていると思っている。
欧米人 アラビア語なみにどれも難しいと思っている。

日本語も韓国語も漢字派生の言語なので似ているところはあるけれど、大和言葉和製漢字トバキマル朝鮮製漢字もあるわけで漢字が輸入される以前から存在して生活に根差した言葉である以上無視できない。発音もそれぞれ独自の発展を遂げている。中国国内など発音すら統一されていなくて地方が違うと通じなかったりする。日本語の発音は簡単ともいわれるが、 中国語、韓国語の学習ビデオで現地語ネイティブが発音する日本語を聴くと相当日本語がお上手な人でも違うな、と思うことはかなりあるしやはり異国の言葉というものは結構難しい。

肘を逆に曲げてみた

以前記事を書いたときより肘の逆に曲がる角度が激しくなってきた。関連:人間の腕は逆にも曲がるのが普通




猿腕 double jointed elbow

超の猿腕。きもちわる。

いつもこんなに曲がるわけではないが、それでも「腕ぐにゃぐにゃですね」とか言われるわけだ。見られた人からどうやるんですかとか聞かれたところで、単に肘が逆に曲がるだけだし。でも90度超えるとは思わなかった。

アドビのストックフォトに載ってるような、 渋野日向子なみに腕を伸ばして肘をくっつけるのは誰でもできるようになるだろうし、そうでなくとも、うまく押してやれば多くの人は両肘をくっつけるくらいはできる(何人かで試した)。それ以上なら亜脱臼させることになるから誰でもできるかどうかは分からない。もともと大きく逆に曲がる構造ではないし骨折とまではいかなくても、肘部管症候群肘内障、関節炎、外反肘くらいにはなるかも。



コントーショニストでもここまで肘を過伸展させる人は見かけないし、猿腕が特技とか言ってる人でも90度越えはそう居ないだろうと思ったが、世の中には180度逆に曲げられる人もいるらしい (何かの手術後) 。

C++/CLIでExcelを操作してみる。

オワコンのC++/CLIで、Excelを動かすコンソールアプリの雛形っぽいものを作った。

CppCliExcel.cpp
WordPressで壊されるので半角の<>は全角の<>に置換している。

#using <System.dll>
using namespace System;

// Excel関連
#using <System.Runtime.InteropServices.dll>
#using <C:/Program Files (x86)/Microsoft Visual Studio/Shared/Visual Studio Tools for Office/PIA/Office15/Microsoft.Office.Interop.Excel.dll>
namespace Excel = Microsoft::Office::Interop::Excel;


int ExcelWork(void) {
    int Ret = 0;    // 途中でエラーが発生したら!0。
    
    Excel::Application^ oApp = nullptr; // Excelアプリケーション
    Excel::Workbook^ oWBook = nullptr;  // ワークブック
    
    try {
        // Excel開始
        oApp = gcnew Excel::Application();
        oApp->Visible = true;
        
        // ワークブックを新規追加、操作対象のワークシートを選択
        oWBook = oApp->Workbooks->Add(Type::Missing);
        Excel::Worksheet^ oWSheet = static_cast<Excel::Worksheet^>(oWBook->Worksheets[1]); 
        oWSheet->Name = "CppCliExcel";  // シート名を変更
        
        // セルに書き込み
        oWSheet->Cells[1,1] = L"C++/CLI Excel"; // Cellで
        oWSheet->Range["A2:B3", Type::Missing]->Value2 = 1234;  // Rangeで

        // セルから読み出し
        String^ strval = static_cast<Excel::Range^>(oWSheet->Cells[1,1])->Text->ToString(); // Rangeを経由して値を取得
        long lngval = Convert::ToInt32(static_cast<Excel::Range^>(oWSheet->Cells[2,1])->Text);  //Convert::ToInt32で数値に変換
        Console::WriteLine("A1={0},B1={1}", strval, lngval);    // コンソールに表示

        // 別名保存
        oApp->DisplayAlerts = 0;
        oWBook->SaveAs(L"CppCliExcel-Out.xlsx", Type::Missing, Type::Missing, Type::Missing, Type::Missing, Type::Missing, Excel::XlSaveAsAccessMode::xlNoChange, Type::Missing, Type::Missing, Type::Missing, Type::Missing, Type::Missing);
    }
    catch(Exception^ e) {
        Console::WriteLine("Exception:\n" + e);
        Ret += 10;
    }
    finally {
        // ワークブックを閉じる
        if(oWBook != nullptr) {
            oWBook->Close(false, Type::Missing, Type::Missing);
            oWBook = nullptr;
        }
        
        // Excel終了
        if(oApp != nullptr) {
            oApp->DisplayAlerts = false;    // 警告表示オフ
            oApp->Quit();   // Excel終了
            Runtime::InteropServices::Marshal::ReleaseComObject(oApp);
            oApp = nullptr;
        }
    }
    
    // ガベコレ
    GC::Collect();
    GC::WaitForPendingFinalizers();
    GC::Collect();

    return Ret;
}

int main(array<String^>^ args) 
{
    ExcelWork();
    return 0;
}

ビルドと実行は次の通り。Microsoft.Office.Interop.Excel.dllのパスは変えないといけないかも。

cl /clr CppCliExcel.cpp && CppCliExcel

内容としてはC#でできることをC++/CLIに置き換えただけ。ここでは使っていないがCライブラリやSTLと直接連携できるからそれらの資産がある場合は役に立つかもしれない。開発系の職場でもなければ VBAくらいは使っても C++/CLIまで知ってる人はあまりいないから相手を煙に巻くくらいには使えると思う。(何の仮想敵と戦っているのかは不明。)

市販のラジオで聞く海外の放送。

今普通に売っているラジオ(ICF-M780N)だけで自宅に居ながら明瞭に聴ける海外の放送を調べてみた。場所は中京圏、太平洋側。

★聞こえた、良く聞こえる。
603kHz KBS第2ラジオ 500kW 韓国
621kHz 平壌放送 1500kW 北朝鮮 
657kHz 平壌放送 1500kW 北朝鮮
711kHz KBS第1ラジオ 500kW 韓国
801kHz 平壌放送kHz 1500kWkHz 北朝鮮
810kHz AFN American Forces Network 50kW 日本
945kHz CNR中央人民広播電台  中国
972kHz KBS韓民族放送 第1放送 1500kW 韓国
981kHz CNR中央人民広播電台  中国
1017kHz CRI中国国際放送  中国
1044kHz CRI中国国際放送 500kW 中国
1134kHz KBS第3ラジオ 500kW 韓国
1170kHz KBS韓民族放送 第2放送 500kW 韓国
1206kHz 延辺人民広幡電台  中国 
1566kHz FEBC済州極東放送 250kW 韓国

夜間にはこれらの放送は室内でも簡単に受信できて、混信対策としてラジオの向きを変える程度で国内の放送と変わらない。ラジオを改造したり外部アンテナは使わない方針として、市販のラジオでもデジタルの周波数表示があるもののが苦労はしない。カーナビのラジオ機能でもだいたい受信できるし、むしろ室内より良いくらい。昼間はAFN 810kHz以外は聞こえなくて、夕方から夜間にかけて聞こえるようになってくる。大半が半島からの電波で国内向けや対北向けが普通に入って、やはり隣国なのだと実感する。朝鮮語をちょっとだけ聞きとれるようになってきたから個人的にはちょっと面白いが、国内の深夜放送リスナーに煙たがられる存在でもある。

次の放送局は時期や時間と運によっては聞こえるかもしれないもの。今回は聞こえなかった。国内AM民放が終了していったら海外のAM放送はもっと聞きやすくなるか、あるいは海外の放送局もAM放送をやめてしまうのか。

★聞こえなかったが、聞ける可能性がある。
603kHz CBS 1000kW 台湾
585kHz アジアの声 1500kW 台湾
648kHz ロシアの声 1000kW ロシア
783kHz ロシアの声 1000kW ロシア
927kHz CBS 1200kW 台湾
1080kHz 朝鮮中央放送 1500kW 北朝鮮
1098kHz ウラジオストック 1000kW ロシア
1143kHz VOA 1000kW フィリピン
1521kHz CBS 1200kW 台湾

夏前の朝夕や真夏の昼間などのEスポシーズンは、FM放送でも中韓の放送も聞こえるときがある。安定している時間が短いし、基本的に国内向け放送でネイティブ発音の速度なので放送局を特定するのが難しいのが残念。AM放送より明るい雰囲気の番組が多い気がする。

Office開発をするのにOfficeを買わなくてもよいという事実。

一般的なOffice開発はMSDN Professional以上があれば十分※で、Officeを買う必要が無い。

以前はMS Office開発をしたいならパッケージのOffice DeveloperかMSDN Level3/Universal/Enterpriseを使う必要があって通常のVBA埋め込みブックを超える開発に手を出すのはなかなか壁が高かった。一番安上がりなOffice Developer(Office本体と、VBAエディタでコンパイルできるようになる謎の開発環境と、コードサンプルの詰め合わせ)でも10万円近く。MSDN ProレベルでOffice2003とVisual StudioでVSA開発したければ Visual Studio Tools for the Microsoft Office Systemsとか買わないといけなかったりもしたはず。

今はVisual Studio Pro以上にVSTOが付いてるから、後は普通のOfficeがあれば開発に着手できるんだけど、2019年4月に出てきたOffice365開発者用ライセンス(Office 365 E3 Developer)は開発用Office365がなんと完全に無料。製品版1年に対して、使用期限が3か月と短い以外は普通に企業向けOffice365なので、PCインストール版のExcelとかOutlookとかのOfficeアプリも使える。もうお高いOfficeを買わなくていい。しかも90日間の期間限定で一見試用版は、Office開発の何かをいじっている限り90日が自動延長される仕組み。

春ごろにMSDNのBenefitsから申し込みしたが、これもMSDNが必須というわけでもない。

で、今回無事に自動延長がかかった。MSDNから申し込みした場合の有効期限は「Visual Studio Enterpriseまたは Visual Studio Professional を通じてプログラムに参加する場合、Visual Studio のサブスクリプションの有効期限が切れるまでサブスクリプションが自動的に更新します。 」となっているものの、今回開始したMSDNサブスクリプションはすでに期限切れだし。

何をしていたかというと、期間中Visual StudioでC#なVSTOプロジェクト(ローカルのExcel)をちょこちょこいじってビルドアンドデバッグしてただけ。これだけでOffice365もPCにインストールできるOfficeも(あくまで開発用として)自由に使えるっていうのはこれまでのことを考えると画期的だ。

最近はOffice開発をサボッていて次回の自動延長がかかるかは不明。まあ、消されたら再登録すればいいんだけど。

PCem v15を試してみた。

PCemが5月にv15になっていた。

PCem
https://pcem-emulator.co.uk/

今回のアップデートで個人的にナイスなポイントはマシンでASUS P/I-P55T2P4が対象になったこと、CPUの種類にAMD K6/K6-2(up to 300MHz)が追加になったこと。他にもIDT WinChip2も追加になってるとか、IBM PCのカセット読込みができるとか試すに試せないようなよくわからないのもある。

P55T2P4はATX版を使っていたし、AMD K6-2は動態保存してるし。MSDNで入手できるMS-DOS6.22+Win3.11(English)をセットアップ。

ちょっとマウスカーソルがカクカクするところやキーリピートが遅いのはV14から変わらない。

VB.netでメモリ解放アプリ

VB.netでメモリ解放アプリを作った。実際はこんなもの使う必要ないのだが、VB.netをまともに使ったことが無かったし、64ビット版Windowsでもこんなものの効果あるのか試したかった。Windows95の時代だってこの手のアプリは使う必要なんて全くなかった。それでもいまだに山ほど出てるし、さらにスマホ版も山ほど出ている。 世の中のシッタカちゃん達は物理メモリの空きにうるさいのだ。

※どうしてもこの操作を行いたいならWindowsならWindows2003リソースキットツールのempty.exeを使うのが一番安全だと思う。

主要な処理はVBでAPIを使わずに組めるってところがポイント。APIを使わないのでメモリ確保量は手動で指定。

Module Module1
    Class Mem1GB
        Const MemSize As Int32 = 26214400  '一度に確保するメモリ量(1GB=268435456,100MB=26214400) 1GB = 1024[Bytes]*1024[k]*1024[M] / 4[Bytes/Int32] 

        Dim Mem() As Int32
        Public Sub New()
            ReDim Mem(MemSize)
            Dim I As Long
            For I = 0 To MemSize - 1 Step 1024  '物理メモリを使用するため、1ページごと1個だけ値を書いてアクセスする 1Page = 4kB = 4*1024 / 4[Bytes/Int32]
                Mem(I) = I
            Next
        End Sub

        Protected Overrides Sub Finalize()
            ReDim Mem(0)
            System.GC.Collect()
        End Sub

        Public Function Check() As Boolean
            Check = False

            Dim N As Int32 = Int(Rnd() * Mem.Length / 1024) * 1024
            If N = Mem(N) Then
                Check = True
            Else
                System.Console.WriteLine("Check({0}) = {1} : NG.", N, Mem(N))
            End If

        End Function

    End Class

    Sub Main()
        Dim AllocSize As Long = 20
        If Environment.GetCommandLineArgs.Length >= 2 Then
            AllocSize = Environment.GetCommandLineArgs(1)
        End If


        System.Console.WriteLine("Allocate {0}GB", AllocSize / 10)

        Dim NewMem() As Mem1GB
        ReDim NewMem(AllocSize)   ' 100MB単位
        For Itr = 0 To NewMem.Length - 1
            NewMem(Itr) = New Mem1GB()
        Next

        System.Console.WriteLine("Memory allocated.")

        For Each Itr In NewMem
            If Itr.Check() = False Then
                System.Console.WriteLine("Memory read error.")
                System.Console.ReadKey()
            End If
        Next

        System.Console.WriteLine("Checking Done.")

        For Itr = 0 To NewMem.Length - 1
            NewMem(Itr) = Nothing
        Next
        System.GC.Collect()

        System.Console.WriteLine("Garbage collection Done.")
    End Sub

End Module

WordPressで崩れるため<、>、;は全角に置換。VS2019とかのVB.netコンパイラでx64アプリとしてビルドする。32ビット環境で使うならx86でも良い。

コマンドプロンプトで確保したいメモリの100MB単位の量を引数に指定して実行。未指定だと2GB確保する。次の例は15GBのメモリを確保する。

VBNewMem 150

タスクマネージャーの「利用可能」の値より少し少なめを指定するのが一番効率が良い。どのくらい少なくするかは環境依存。多すぎるとスラッシングしまくりでなかなか終わらない。

タスクマネージャーで見ながら動かすとどういう動きをするかがわかる。 大量のメモリを確保して、解放するだけ。キャッシュ部分が破棄されて物理メモリに空きができるという仕組み。大半のキャッシュは読み取り済みキャッシュなのですぐに破棄される。書き込み待ちキャッシュはディスクに書き出さないといけないのでおそらく終盤でイヤイヤ吐き出されるのだと思う。

何もしないコードの中身は本当に何も無くなる。

CompJapan的ソフトを作ったらどうなるか試してみる。

驚速メモリを使って、20年ほど前に「メモリ最適化を行うとうたった実際には何もしないソフトをシェアウェアとして販売した」事案があったのを思い出した。今でもGoogle Playストアに行けばこの手のソフトには山ほど出逢えるからこんな子供にいちいち付き合ってるほど今のインターネットには余裕が無い。

Google Playトップ人気の有料アプリ、実態は中身なしの詐欺アプリhttps://www.itmedia.co.jp/news/articles/1404/08/news037.html

探せば誰かがアーカイブしたデジタルタトゥーが出てくるが、手っ取り早くWikipediaで調べなおした。それによると「一つの変数に定数を足して引くことを36万回繰り返す」処理を行っているらしい。VBのソースも載っている。

For Bbbb = 1 To 3000
Print #1, Jjjj 'CPU処理のためのPrint文
For Kkkk = 1 To 120
Kkkk = Kkkk + 65468543
Kkkk = Kkkk - 65468543
Next Kkkk
Next Bbbb

確かに時間かせぎ以外は何もしていない。メモリの消費も最小限だし。VB.netで書き直してみた。 前後が載ってないからファイル番号の#1が何なのか良くわからない。(←後で判明した)

'newmem.bas
Module Module1
    Sub Main()
        For Bbbb = 1 To 3000
            'Print #1, Jjjj 'CPU処理のためのPrint文
            For Kkkk = 1 To 120
                Kkkk = Kkkk + 65468543
                Kkkk = Kkkk - 65468543
            Next Kkkk
        Next Bbbb
    End Sub
End Module

vbcでコンパイルする。vbc newmem.bas
vbcのバージョンはMicrosoft (R) Visual Basic Compiler バージョン 3.100.119.28106 (58a4b1e7)。実行しても一瞬で終了して何も起こらないので、どういう処理がなされたか逆アセンブルしてみる。ildasm newmem.exe で、Module1の中身を見てみる。

.method public static void  Main() cil managed
 {
   .entrypoint
   .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
   // コード サイズ       43 (0x2b)
   .maxstack  2
   .locals init (int32 V_0,
            int32 V_1)
   IL_0000:  nop
   IL_0001:  ldc.i4.1
   IL_0002:  stloc.0
   IL_0003:  ldc.i4.1
   IL_0004:  stloc.1
   IL_0005:  ldloc.1
   IL_0006:  ldc.i4     0x3e6f87f
   IL_000b:  add.ovf
   IL_000c:  stloc.1
   IL_000d:  ldloc.1
   IL_000e:  ldc.i4     0x3e6f87f
   IL_0013:  sub.ovf
   IL_0014:  stloc.1
   IL_0015:  ldloc.1
   IL_0016:  ldc.i4.1
   IL_0017:  add.ovf
   IL_0018:  stloc.1
   IL_0019:  ldloc.1
   IL_001a:  ldc.i4.s   120
   IL_001c:  ble.s      IL_0005
   IL_001e:  ldloc.0
   IL_001f:  ldc.i4.1
   IL_0020:  add.ovf
   IL_0021:  stloc.0
   IL_0022:  ldloc.0
   IL_0023:  ldc.i4     0xbb8
   IL_0028:  ble.s      IL_0003
   IL_002a:  ret
 } // end of method Module1::Main

0x3e6f87fは10進で65468543で、その直後にadd.ovf、sub.ovfのオペコードがある。他にも120とか、0xbb8(10進で3000)とか出てるし、忠実にilアセンブラに置き換わっているようだ。当のシェアウェア作家もVBを使っていたということだから、Standardでなければ最適化機能もあった気がするし、こういうコードは無視されるんじゃないかと思った。

今どきのVB.netコンパイラ vbcで最適化を有効にしてコンパイルしてみる。vbc -optimize+ -debug- newmem.bas
ilアセンブラは次のような感じ。

.method public static void  Main() cil managed
 {
   .entrypoint
   .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
   // コード サイズ       42 (0x2a)
   .maxstack  2
   .locals init (int32 V_0,
            int32 V_1)
   IL_0000:  ldc.i4.1
   IL_0001:  stloc.0
   IL_0002:  ldc.i4.1
   IL_0003:  stloc.1
   IL_0004:  ldloc.1
   IL_0005:  ldc.i4     0x3e6f87f
   IL_000a:  add.ovf
   IL_000b:  stloc.1
   IL_000c:  ldloc.1
   IL_000d:  ldc.i4     0x3e6f87f
   IL_0012:  sub.ovf
   IL_0013:  stloc.1
   IL_0014:  ldloc.1
   IL_0015:  ldc.i4.1
   IL_0016:  add.ovf
   IL_0017:  stloc.1
   IL_0018:  ldloc.1
   IL_0019:  ldc.i4.s   120
   IL_001b:  ble.s      IL_0004
   IL_001d:  ldloc.0
   IL_001e:  ldc.i4.1
   IL_001f:  add.ovf
   IL_0020:  stloc.0
   IL_0021:  ldloc.0
   IL_0022:  ldc.i4     0xbb8
   IL_0027:  ble.s      IL_0002
   IL_0029:  ret
 } // end of method Module1::Main

だっさ。ほぼ変わってない。マネージドコードの実行時最適化もあるかもしれないがもうちょっと何とかならないのか。予想では、ループ内の処理がごっそり抜け落ちて「当時、件のソフトはソースに書いてあることすら本当に実行されてなかったんじゃないか」とか予想したかったのに。あまりにもつまらないのでC++で書き直してみる。<と;は全角文字に置き換え。

int main(void) {
 for(long Bbbb=1; Bbbb<=3000; Bbbb++) {
     for(long Kkkk=1; Kkkk<=120; Kkkk++) { 
        Kkkk = Kkkk + 65468543;
         Kkkk = Kkkk - 65468543;
     }
 } 
return 0;
 }

cl /Fa newmem.cpp でアセンブラソースを書き出す。clのバージョンは最新の Microsoft(R) C/C++ Optimizing Compiler Version 19.21.27702.2 for x64。

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.21.27702.2 
 include listing.inc
 INCLUDELIB LIBCMT
 INCLUDELIB OLDNAMES
 PUBLIC    main
 pdata    SEGMENT
 $pdata$main DD    imagerel $LN9
     DD  imagerel $LN9+90
     DD  imagerel $unwind$main
 pdata    ENDS
 xdata    SEGMENT
 $unwind$main DD    010401H
     DD  02204H
 xdata    ENDS
 ; Function compile flags: /Odtp
 _TEXT    SEGMENT
 Kkkk$1 = 0
 Bbbb$2 = 4
 main    PROC
 ; File C:\Users\xxx\newmem.cpp
 ; Line 10
 $LN9:
     sub rsp, 24
 ; Line 12
     mov DWORD PTR Bbbb$2[rsp], 1
     jmp SHORT $LN4@main
 $LN2@main:
     mov eax, DWORD PTR Bbbb$2[rsp]
     inc eax
     mov DWORD PTR Bbbb$2[rsp], eax
 $LN4@main:
     cmp DWORD PTR Bbbb$2[rsp], 3000        ; 00000bb8H
     jg  SHORT $LN3@main
 ; Line 14
     mov DWORD PTR Kkkk$1[rsp], 1
     jmp SHORT $LN7@main
 $LN5@main:
     mov eax, DWORD PTR Kkkk$1[rsp]
     inc eax
     mov DWORD PTR Kkkk$1[rsp], eax
 $LN7@main:
     cmp DWORD PTR Kkkk$1[rsp], 120     ; 00000078H
     jg  SHORT $LN6@main
 ; Line 15
     mov eax, DWORD PTR Kkkk$1[rsp]
     add eax, 65468543               ; 03e6f87fH
     mov DWORD PTR Kkkk$1[rsp], eax
 ; Line 16
     mov eax, DWORD PTR Kkkk$1[rsp]
     sub eax, 65468543               ; 03e6f87fH
     mov DWORD PTR Kkkk$1[rsp], eax
 ; Line 17
     jmp SHORT $LN5@main
 $LN6@main:
 ; Line 18
     jmp SHORT $LN2@main
 $LN3@main:
 ; Line 19
     xor eax, eax
 ; Line 20
     add rsp, 24
     ret 0
 main    ENDP
 _TEXT    ENDS
 END

忠実にコンパイルというか、トランスレートされている。
次に最適化有効でコンパイル。cl /O2 /Fa newmem.cpp

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.21.27702.2 
 include listing.inc
 INCLUDELIB LIBCMT
 INCLUDELIB OLDNAMES
 PUBLIC    main
 ; Function compile flags: /Ogtpy
 ;    COMDAT main
 _TEXT    SEGMENT
 main    PROC                        ; COMDAT
 ; File C:\Users\xxx\newmem.cpp
 ; Line 19
     xor eax, eax
 ; Line 20
     ret 0
 main    ENDP
 _TEXT    ENDS
 END

やった。ものの見事に何も無くなった。VB.netコンパイラは怪しいが、C++コンパイラは本当に無駄なことはきちんと除外してくれる。C/C++ Optimizing Compilerの名を冠しているだけのことはあるね。


探したらすぐにオリジナルのソースも出てきて、謎のPrint #1, Jjjjの処理内容も分かったから、メモリ最適化処理を忠実に移植(?)したバージョンができた。powershell -C Measure-Command {.\newmem.exe} で確認したら実行にかかる時間は420ミリ秒くらい。

Module Module1
     Sub Main()
         Dim FileNumber1 As Integer = FreeFile()
         Dim AppPath As String = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
         FileOpen(FileNumber1, AppPath & "\log.dat", OpenMode.Output)
         Dim Jjjj = "Data Error none…"
         For Bbbb = 1 To 3000
             PrintLine(FileNumber1, Jjjj)
             For Kkkk = 1 To 120
                 Kkkk = Kkkk + 65468543
                 Kkkk = Kkkk - 65468543
             Next Kkkk
         Next Bbbb
         FileClose(FileNumber1)
         System.IO.File.Delete(AppPath & "\log.dat")
     End Sub
 End Module

外側のループ1回ごとファイルに”Data Error none…”と書いて最後に消す。これならファイル書込時キャッシュ領域作成と破棄の動作で物理メモリを若干解放できるかもしれない。まあ、他にもやってない処理をやってますみたいに見せかけたのはいただけないから擁護のしようもないけど。