マークの魔法倍増

2026/04/11 18:03

マークの魔法倍増

RSS: https://news.ycombinator.com/rss

要約

Japanese 翻訳:

記事は、低消費電力のプロセッサ(完全な浮動小数点ユニット (FPU) を備えていないもの)において単精度浮動小数点乗算を高速化するための新しい RISC-V 拡張機能である Xh3sfx の導入について述べる。このアプローチは、遅いソフトウェアルーチンに依存するのではなく、特殊なハードウェアロジックを活用するものである。設計では、ARM アーキテクチャで以前に使用されていたビット操作のトリック(具体的には Mark Owen による最適化)に適応し、RISC-V 固有の命令と組み合わせて、乗算のレイテンシを 30 サイクル に達成している。これは、標準的な「教科書方式」の方法に必要な 33 サイクルよりも著しく速いものである。

現在の拡張機能は乗算に焦点を当てているが、14 サイクル以内に加算処理も行う。この設計は RP2350 チップ上で成功裏にタペアウトされており、Cortex-M0+ マイクロコントローラーのような微小デバイスにおける実用上の妥当性を示した。このアプローチは、完全なハードウェア FPU や純粋なソフトウェアエミュレーションと比較して、シリコンエリアを削減し、プロセッササイクル数を節約する。研究者たちは現在、同様の戦略を将来の倍精度計算へ拡張できるかどうかを探っている。

本文

この投稿の主題は、私が特に親しみ深かったり熱中したりしている分野です。つまり、組み込みプロセッサにおける単精度浮動小数点乗算の話です。

まず、なぜ最近このトピックにこれほど没頭してきたのかという背景から始め、私が独自に考案した実装手法を解説し、最後に 32 ビット組み込みコア向けの浮動小数点乗算に関するマーク・オーウェン(Mark Owen)氏の極めて大胆なトリックについて深掘りします。このトリックこそが、今回の投稿のそもそものインスピレーション源です。

⚠️ 注記:この記事には「浮動小数点」が含まれています。 カリフォルニア州当局によれば、浮動小数点は哺乳類二足動物(人間)に混乱と恐怖反応を引き起こすと知られています。標準的な推奨事項としては「Computer Scientists Who Should Know About Floating-Point Arithmetic Every」(『コンピューターサイエンティストが知っておくべき浮動小数点算術』)があります。また、実際の IEEE 754-2008 規格は、基数(radix)が 2 でないというファンタジー小説を無視すれば、意外に簡潔かつ読みやすいものです。より触覚的な体験をお探しであれば、IEEE 754 カルキュレーターでバイナリ値(binary16 から始めるのが良いでしょう)をポコポコ弄ってみてください。

ハードでもソフトでもない中間領域

最近、軟質浮動小数点ルーチンの高速化を目指したカスタム RISC-V 拡張命令セット「Xh3sfx」の開発に取り組んでいます。これは FPU を持つケースと持たないケースのちょうど中間地点にあたるもので、未だ十分に探求されていない空間だと感じています。「ファーム浮動小数点(firm floating point)」と呼ぶかもしれません。

C プログラムを、浮動小数点ハードウェアを持たないターゲット用にコンパイルする際、コンパイラは float 変数に対してリクエストされた操作を実行するために、

libgcc
compiler-rt
のようなランタイムライブラリへの呼び出しを挿入します。これを「浮動小数点エミュレーション」と呼ぶこともありますが、それは単に IEEE 754 規格で指定された浮動小数点演算を実装するいくつかのアプローチの一つに過ぎません。

Xh3sfx がカスタム拡張命令セットとはいえ、フォークしたコンパイラーを維持・配布するために名乗りを挙げるわけではありません。コンパイラの実行ルーチンを加速版のものに置換する方が簡単です。新しいルーチンは、浮動小数点フォーマットの難解で不細工な部分を処理するために数種の専用 ALU 操作を使い、実際の計算には通常の整数命令を混在させています。ランタイムライブラリは大部分が文書化され安定した API を有しており、プログラムへの追加支持は加速ライブラリンクやビルドソースへの配置のみで実現できます。これは組み込みファームウェアにとっては合理的なアプローチです。

Xh3sfx は数百ゲートのわずかなコストに対して、単精度の足し算を 14 サイクル、乗算を 16 サイクル(関数呼び出しオーバーヘッドを無視)を実現します。(他にもできることはありますが、これらは例にすぎません。)質的な面で言えば、これは浮動小数点を「ああ、神さま、なんでこんなに遅いのよ」という状況から、一般的なアプリケーションコードや軽量オーディオ DSP では「ただ動作する(Just Works™)」状態へと転換させます。元々は Mastodon でこれを投稿しましたが、命令セットの詳細についてはここ、ライブラリルーチンについてはこっちをご覧ください。

Xh3sfx を用いた乗算

Xh3sfx ライブラリのデフォルト単精度乗算実装は以下の手順を踏みます:

  1. 二つの浮動小数点入力から指数と有効桁( significand )をパッキング解除する。
  2. 正確な有効桁積を、32 ビット×32 ビット→64 ビットの乗算(
    mul
    ,
    mulh
    )を用いて計算する。
  3. 積を 32 ビットレジスタに圧縮し、丸め方向を保持した状態で格納する。
  4. 積を正規化する。
  5. 元の指数の和と組込みを行い、最終的な浮動小数点結果を得る。

具体的にはこのようになります:

__mulsf3:
    // 指数をパッキング解除
    h3.bextmi a2, a0, 23, 8
    h3.bextmi a3, a1, 23, 8
    // 特殊ケース:入力片方が 0 / 劣化数/NaN/無限大である場合
    h3.fcheck2e.s t0, a2, a3
    bnez t0, __mulsf_special_exponent
    // 単精度有効桁を Q3.29 としてパッキング解除
    h3.funpackq3.s a4, a0
    h3.funpackq3.s a5, a1
    // Q3.29 × Q3.29 → Q6.58 を計算
    mul a1, a4, a5
    mulh a4, a4, a5
    // 下部小数節のスティッキービットを収集; a4 は実質的に Q6.26 となる
    snez a1, a1
    or a4, a4, a1
    // 新しい指数を計算;
    // -127 は冗長なバイアス用、+3 は Q6→Q3 のオフセット用
    add a2, a2, a3
    add a2, a2, a5
    addi a2, a2, -127 + 3
    // 丸め付き単精度パッキング
    h3.fpackrq3.s a0, a4, a2
    ret

h3.*
で始まる命令は、Hazard3 カスタム拡張セットに属しており、特に
h3.bextmi
は Xh3bextm 拡張、「残り」は Xh3sfx 拡張から来ています。ALU 操作と取り上げられないフォワード分岐はそれぞれ 1 サイクルであり、関数呼び出しオーバーヘッドを無視すれば全体の遅延は 16 サイクルになります。

この実装は

mul
mulh
が同等に高速であり、かつすべての入力に対して正しく丸められた結果が必要な場合の最適解です。約 0.5 ulp の誤差を許容できる場合は 2 サイクル節約が可能です(これを読者課題として残しておきます;私にもいつか言いたかったのです)。

コンventional(学校教則)乗算

Hazard3 では、乗算用のハードウェア構成が 3 つ用意されています:

  • Minimal(最小):すべての除算・乗算命令はシークウェンシャルな乗算/除算回路で実行されます。通常、1 サイクルまたは 2 サイクルごとのビット処理に設定され、符号補正のために数サイクル追加がかかります。
  • Intermediate(中間):32×32→32 ビットの乗算は専用高速乗算器で実行され、残りの
    mulh/mulhu/mulhsu
    はシークウェンシャル回路で実行されます。
  • Full(フル):すべての乗算が専用高速の 32×32→64 ビット乗算器で実行されます。除算は引き続きシークウェンシャル回路で実行されます。

これらのオプションは、パフォーマンスと面積コストの両方において昇順に並べられています。RP2350 に Tape-out されたのはフル構成の 32×32→64 ビット乗算です。最小構成(シークウェンシャル乗算/除算のみ)の場合、前述の

mul; mulh
実装が再び最適となります。オプション 2 も興味深く、M 拡張で圧倒的に頻繁に実行される命令である
mul
に対してバランスの取れた設計だからです。

この構成に向けた最初の最適化試みでは、32×32→64 ビットの乗算を四個の 16×16→32 ビット乗算に分けることに成功しました。これらはそれぞれ

mul
命令を使って 1 サイクルで実行されます。

__mulsf3:
    // 指数のパッキング解除とチェック
    h3.bextmi a2, a0, 23, 8
    h3.bextmi a3, a1, 23, 8
    h3.fcheck2e.s t0, a2, a3
    bnez t0, __mulsf_special_exponent
    // 乗算を容易化するために有効桁を符号なしとしてパッキング解除
    h3.funpacku3.s a4, a0
    h3.funpacku3.s a5, a1
    // 符号と指数の計算;a2/a3 を解放する
    xor a0, a0, a1
    add a1, a3, a2
    addi a1, a1, -127 + 3
    // U3.29 × U3.29 → U6.58 を計算 (32x32 -> 64)
    srli a2, a4, 16
    srli a3, a5, 16
    zext.h a4, a4
    zext.h a5, a5
    mul t0, a2, a3  // A_h * B_h
    mul t1, a2, a5  // A_h * B_l
    mul a2, a4, a3  // A_l * B_h
    mul a4, a4, a5  // A_l * B_l
    // 交差項の和を計算;hi[16] へのキャリー保存
    add t1, a2, t1
    sltu t2, t1, a2
    // 交差項を加算して低単語へ;hi[0] へのキャリー保存
    slli a2, t1, 16
    add a4, a4, a2
    sltu a3, a4, a2
    // キャリーを正しい重み付けでパッキング
    pack a3, a3, t2
    // 高単語:A_h * B_h + (交差項 >> 16) + ci0 + (ci1 << 16)
    srli t1, t1, 16
    add a5, t0, t1
    add a5, a5, a3
    // 最終積完了:U6.58 が a5:a4 に格納。下部スティッキービットを収集。
    snez a4, a4
    or a5, a5, a4
    // Q3 へ再正規化
    h3.feadju3 a4, a5
    h3.ssra a5, a5, a4
    add a1, a1, a4
    // パッキング前に符号を適用。有効なのは上部 U3.29 のみ。
    h3.xorsign a5, a0, a5
    h3.fpackrq3.s a0, a5, a1
    ret

これは馴染みの深い二項積です:$(x_1 + x_0)(y_1 + y_0) = x_1y_1 + x_1y_0 + x_0y_1 + x_0y_0$。$A = a_1 \times 2^{16} + a_0$(ここで $a_1, a_0$ は 32 ビット A の 16 ビット半分)と置けば、積 $AB$ は四個の 16×16→32 ビット乗算の結果の和にいくつかの $2^n$ (即ちシフト)因子を伴って展開されます。

多くの時間は乗算そのものではなく、ビットを正しい場所へルーティングする処理で消費されています。特にキャリーの伝播は非常に複雑です。RISC-V で最も過小評価されている命令

pack
の助けも借りられていますがです。この関数の本体実行には 33 サイクルかかります。これはまだ十分立派ですが、
mul; mulh
バージョンの約 2.5 倍という実行時間となります。

上記コードをさらに改善するのは困難です。もし試みようとすれば、文献は乗算回数を減らすことに没頭していることに直面するでしょうが、短いパイプラインにおいては

mul
は他の任意の整数 ALU 操作と同じコストを持ちます。例えば Karatsuba 乗算は部分的積の乗算を四個から三個へ減らすような整った恒等式です。これはスカラーに対するストラスゼンのアルゴリズムのようなものです。残念ながら、設定および撤去のコストをもたらすとともに、33 ビットの中間値を扱う必要があるという要件があります。計算作業は行っていませんが、感覚的には遅くなるはずです。おそらく積サイズ対乗算器サイズの比率が大きい場合に有用で、递归による複合的節約が得られるでしょう。

この実装に満足していましたら、マーク・オーウェン氏が無作為にメールを持ってきてくれたこのトリック(Armv6-M)に出会いました。

    lsls r0,#8     @ x のマンティサを左シフト
    lsls r1,#8       @ y のマンティサを左シフト
    lsrs r0,#9      // 9 ビット右シフト(符号なし仮定)
    lsrs r1,#9

    adds r2,r0,r1    // 後続用
    mov r12,r2
    lsrs r2,r0,#7    @ x[22..7] Q16
    lsrs r3,r1,#7    @ y[22..7] Q16
    muls r2,r2,r3    @ 結果 [45..14] Q32:決して過大評価ではなく、最悪の誤差は 
                      // 2*(2^7-1)*(2^23-2^7)+(2^7-1)^2 = 2130690049 < 2^31
    muls r0,r0,r1    @ 結果 [31..0] Q46
    lsrs r2,#18      // 結果 [45..32] Q14
    bcc 1f
    cmp r0,#0
    bmi 1f
    adds r2,#1       // r2 の誤差を修正
1:
    lsls r3,r0,#9    @ 結果の下部からビットをずらす
    lsrs r0,#23      @ Q23
    lsls r2,#9
    adds r0,r2       // cut'n'shut(結合)
    add r0,r12       @ 欠落した 1 の挿入なしに対する補償 (x+y) * 1
;@ 結果 - 1 が r3:r0 に格納 (Q23+32、つまり [0,3) 範囲)

マークは RP2040 ROM 浮動小数点ライブラリの著者であり、彼のメールは常に 80 文字で折り返されています。この関数は単精度乗算の正しく丸められた結果を返しますが、2 つの 32×32→32 ビットの部分積だけで実現されます。また、私のコンベンショナルな乗算に比べて、命令セットが格段に制限されているにもかかわらず、ビット操作や一般論的な議論(waffling)は遥かに少なく済んでいます。

核心となるトリックは、二回の乗算を使用して 23×23→46 ビットの積を計算することです。このトリックは 24 ビットの入力には適用できないため、彼は暗黙の 1 を除外し、単に 23 ビットの小数部分のみを乗算し、後に欠落した分の補償を行うのです。

まず第一段階:

    muls r0,r0,r1    // 結果 [31..0] Q46

この下部の乗算が直接、結果の下位 32 ビットを与えてくれます。この部分は正確です。

第二段階:

    lsrs r2,r0,#7    @ x[22..7] Q16
    lsrs r3,r1,#7    @ y[22..7] Q16
    muls r2,r2,r3    // 結果 [45..14] Q32:決して過大評価ではなく、最悪の誤差は 
                      // 2*(2^7-1)*(2^23-2^7)+(2^7-1)^2 = 2130690049 < 2^31

この上部の乗算は、我々の結果に近い数の上位ビット(45:14)を与えます。これらのビットに対する正確な結果は $(x * y) >> 14$(中間値の切断なし)となるべきですが、代わりに $(x >> 7) * (y >> 7)$ を計算しており、これは近似的で、各側面の 7 つの最低位ビット(LSB)からの寄与を欠いています。

もし高乗算から得られる上位 45:32 ビットを下乗算から得られる低位 31:0 ビットに接合すれば、完全な 46 ビットの結果が得られます。ただし、現時点ではこれは単なる近似的な結果(

approx[45:14]
と呼びましょう)です。マークは誤差 $e$ が $-2^{31} < e \le 0$ であることを計算し、下界を 2 のべき乗に丸めた状態としています。この境界条件は、以下の二つの可能性のみを残します:

  • 結果の上位ビット 45:31 は既に正しい。
  • 結果の上位ビット 43:31 が間違っているが、$2^{31}$ を加えることで修正できる。

この修正は 30:14 ビットを修復しませんが、それは構いません:下乗算からはすでにそれらを得ているからです。修正論理は以下の通りです:

    lsrs r2,#18      // 結果 [45..32] Q14
    bcc 1f
    cmp r0,#0
    bmi 1f
    adds r2,#1       // r2 の誤差を修正
1:

英語に訳せば、上記のコードは「

approx[31]
がセットであり、かつ
exact[31]
がクリアであれば、
approx[32]
をインクリメントする。
approx[31:14]
を廃棄する」と意味します。これは
approx[31]
exact[31]
の異なり部分を
approx[31]
に加算した際のキャリーアウトに等しく、まさに必要な修正です。r2 の下部 14 ビットには今や正確な結果の 45:32 ビットが含まれているため、二回の乗算で完全な 46 ビット積が得られます。

残りのコードは、後の丸め処理のために便利な形にこれらのビットをシフトして結合し、欠落した暗黙の 1 の補償も部分的に行います。

マークにこれを尋ねた際、彼は以下のような説明を提供してくれました(これはエレガントですが、私の脳には少し形状が合いません): (注:テキスト版では図は省略)

「したがって、計算した誤差の範囲を考えると、もし高乗算と下乗算で r[31] が異なれば、正しい修正は高乗算の r[31] をインクリメントすることです。あなたのコードでは、高乗算で r[31] がセットでかつ低乗算でクリアであるという場合にのみ r[32] にインクリメントを適用し、これは r[32] へのキャリーをもたらします。逆に、高乗算でクリアだが低乗算でセットになる場合は r[32] へのキャリーを生じないので、これを無視しているのですね。私の理解は正しいでしょうか?」

「はいです。私はこう考えています:下位 32 ビットは間違いなくすべて正確です。上位半分(高値部分)の積の上位 16 ビットをとる際の最悪の誤差は 2 だけです。したがって、もしこの二つの結果を 2 ビットだけオーバーラップさせることができれば、上位部分へのキャリーは最大一つに限定され、すべてを修正できます。」

私の乗算をより魔法的に

RISC-V ではかなり異なる結果になりますが、このトリックは実際に使用可能で有益であることが分かりました。

__mulsf3:
    h3.bextmi a2, a0, 23, 8
    h3.bextmi a3, a1, 23, 8
    h3.fcheck2e.s t0, a2, a3
    bnez t0, __mulsf_special_exponent
    // ここでは、23 x 23 -> 46 ビットの積を二つの 32 ビット乗算で計算するための 
    // マーク・オーウェン氏のトリックのバリエーションを使用します。
    li t2, -1 << 23
    andn a4, a0, t2           // x - 1, U0.23
    andn a5, a1, t2           // y - 1, U0.23
    bseti t2, a4, 23
    add t2, t2, a5            // x + y - 1, U2.23 (後続で有用)
    xor a0, a0, a1            // 符号
    add a1, a3, a2            // a2/a3 は現在解放済み
    addi a1, a1, -127 + 3     // 指数
    mul a2, a4, a5            // exact[31:0]
    srli a4, a4, 7
    srli a5, a5, 7
    mul a4, a4, a5            // approx[45:14]
    // approx[45:0] の誤差は -2^31 < err <= 0 より少し良好。
    // 二つの可能性のみ:
    //
    // * approx[45:31] が exact[45:31] に等しい
    //
    // * approx[31] と exact[31] が異なる;2^31 を加えると 
    //   上位ビット 45:31 が修正される
    //
    // approx[32] へのキャリーは、approx[31] がセットでかつ exact [31] がクリアの場合に発生する。
    // よって、approx[31] に !exact[31] を加えると、ビット 45:32(のみ)が修正される。
    srli a4, a4, 17
    bltz a2, 1f
    addi a4, a4, 1
1:
    srli a4, a4, 1
    // 今や:exact[45:32] が a4 に、exact[31:0] が a2 に格納。U6.26 でスティッキー LSB と共にパッキング。
    slli a4, a4, 12
    li a5, 20
    h3.ssrlsticky a2, a2, a5
    or a4, a4, a2
    // ここで得たのは:p = (x - 2^23)(y - 2^23)
    //                 = xy - (x + y) * 2^23 + 2^46
    // 既に持っていた:s = x + y - 2^23
    //
    // 望むもの:        xy = p + (s + 2^23) * 2^23 - 2^46
    //                 = p + s * 2^23
    sh3add a4, t2, a4
    // U3.29 へ正規化
    h3.feadju3 a5, a4
    h3.ssrlsticky a4, a4, a5
    add a1, a1, a5
    // パッキング前に符号を適用。
    h3.xorsign a4, a0, a4
    h3.fpackrq3.s a0, a4, a1
    ret

いくつかの違いがあります。一つは、近似乗算の修正が少しずる賢く(cheeky)、ビット 31 までではなくビット 32 から修正される点です。また、暗黙の 1 の処理も完全に異なります。

これにより 3 サイクル節約となり、全体で 30 サイクルの

fmul
になります。気がつかなければなりませんが、これらのすべての関数は RVE レジスタ(x0-x15)に収まるため、Cortex-M0+ クラスのコアでも動作します。

この技術を二重精度乗算における 52×52→104 ビットの内部積のための 32×32→64 ビット乗算に応用できる可能性を感じていますが、まだ証明していません。

⇥ wren.wtf に戻る

同じ日のほかのニュース

一覧に戻る →

2026/04/13 4:44

怠惰と失われた危機の罠

## Japanese Translation: テキストは、ラリー・ウォールのプログラミングにおける「怠け」、不満、そして大それた振る舞いの美徳が依然として不可欠であると論じつつ、特に未来の利用に最適化された単純かつ強力な抽象化を駆使する「怠け」においてはその重要性が高いと指摘しています。これに対して、大規模言語モデル(LLM)は危険に「徳ある怠け」を、「 Hustle Porn」と呼ばれる偽の勤勉で置き換えてしまいました。人間とは異なり、LLM は作業に対してコストを負担せず、時間制約も無視するため、自慢のためのメトリクスによってではなくエンジニアリングの厳密さによってではない、不要なコードの層を蓄積します。この転換は、「Camel Book」という歴史的智慧において、即時の出力量よりも使いやすさを重視する方針と対照付けられます。具体例として、LLM を用いて 1 日 37,000 行ものコードを書き上げたというブロプログラマの Garry Tan の自慢に対し、Gregorein の分析によって多数のテストハネスとゼロバイトのロゴが示されており、これは無制約な AI が肥大化したシステムを生成する様子を明らかにしています。もし無制約のままにされれば、LLM は「ゴミ」の層を積み重ねることで単純な設計ではなく技術的負債の形で未来の世代を脅かすことになります。しかし、業界の行方はエンジニアがこれらの AI モデルを徳ある怠けの方へ導けるかに依存しています。制約と Oxide ガイドラインに導かれ、LLM が複雑性を削減し、厳密な設計を促進して将来に向けてより単純かつ強力なソフトウェア抽象化をもたらすことを保証することが可能です。 ## Text to translate: The text argues that while Larry Wall's programming virtues of laziness, impatience, and hubris remain essential—especially laziness, which drives simple, powerful abstractions optimized for future use—Large Language Models (LLMs) have dangerously displaced "virtuous laziness" with a form of false industry called "hustle porn." Unlike humans, LLMs incur no cost for work and ignore time constraints, causing them to accumulate unnecessary code layers driven by vanity metrics rather than engineering rigor. The summary contrasts this shift with historical wisdom found in the "Camel Book," which prioritizes ease of use over immediate output volume. Examples include broprogrammer Garry Tan bragging about writing thirty-seven thousand lines of code per day with LLMs, while Gregorein's analysis revealed multiple test harnesses and a zero-byte logo, illustrating how unchecked AI generates bloated systems. If left unconstrained, LLMs will threaten future generations with technical debt by building up "garbage" layers rather than simpler designs. However, the industry's trajectory depends on whether engineers can steer these AI models back toward serving virtuous laziness; guided by constraints and Oxide guidelines, we can ensure LLMs reduce complexity and promote rigorous design to yield simpler and more powerful software abstractions for the future.

2026/04/12 21:21

慣用表現に基づくデザインを取り戻そう

## Japanese Translation: 現代の Web アプリケーションは、デスクトップ時代の統一的なインターフェース標準を捨てて、基本的なタスクを第一原理から再発明し、リアルタイムコラボレーションなどの機能に優先順位を置いている。この変化により、ユーザーはチェックボックスによるログイン永続化や標準的なクレジットカード入力フィールドといった馴染み深い「デザイン慣習」に頼るのではなく、新たな相互作用パターンを絶えず学ぶことを余儀なくされている。Figma や Linear などのツールは設計が良くても、共有アイコンやキーボードショートカットの欠如により断片的な体験をもたらしており、OS によって強制されたライブラリによる予測可能な動作を保証した Windows 時代の均質なインターフェースとは対照的である。この増大するユーザー摩擦に対処するためには、HTML と CSS で定義されるコアなブラウザ慣習に回帰すべきであり、開発者はあいまいなアイコンよりも一貫したアクション、信頼できるデフォルト値、明瞭なテキストラベルを優先することで、予測可能性を取り戻し、ユーザーの学習時間を短縮し、UI 標準の全面的な再発明なしにも Web エコシステムへの信頼を再構築できる。

2026/04/13 1:38

# DIY ソフトドリンクの作り方 「DIY ソフトドリンク」というタイトルは適切ですが、コンテンツをさらに充実させるための構成案をご提案します。 ご自身の手に入れた素材や好みの味に合わせて自由にアレンジしてみてください。 --- ## 【必要なもの】 * 炭酸水(またはレモンサワーベースのシロップ) * シュガーシロップ(または蜂蜜、アガベシロップなど) * お好みの果実(レモン、ライム、オレンジなど) * 氷 * ガラス瓶またはペットボトル(中性洗剤で十分に洗浄したものですこと) ## 【基本レシピ】 1. **シロップの調製** 砂糖と水(甘さを抑えたい場合は 2:1 の割合、通常は 1:1)を鍋に入れて、弱火で溶かします。 お好みの果実を加えて香りを出したら、冷まします。 2. **果汁の絞り方** 新鮮な果実をよく洗い、果汁を搾ります。 必要であれば、果肉も一緒に漉すなどして、澄んだ液体に仕上げてください。 3. **混ぜ合わせ** シロップと果汁をお好みの比率で混合します(例:シロップ 2 :果汁 1)。 グラスや容器に移し替えて、冷蔵庫で保存してください。 4. **炭酸水とのミックス** 氷を入れたグラスに、少量の自家製果汁シロップを入れてから、炭酸水を注ぎます。 スパチュラなどで軽く混ぜ合わせれば完成です。 ## 【ポイント】 * 甘さは控えめが基本ですが、お好みで砂糖の量を調整してください。 * 新鮮な果実を使うことで、より自然な香りを堪能できます。 * 保存期間は冷蔵庫に置いても 2〜3 日が目安です。

## Japanese Translation: 本稿は、糖分・カフェインフリーで正確な自家製コーラレシピを開発する革新的なプロジェクトを記録しています。2020 年以降、著者は Open Cola や Cube Cola などのブランドに着想を得て、オレンジ、ライム、レモン、ナツメグ、シナモン(クサヤ)、コリアンダー、ラベンダーといったエッセンシャルオイルとアラビアゴム(天然の乳化剤)を主成分とする配合を開発しました。計測には 1 ml のインシュリンペン用シリンジを用い、科学的手法で精細な定量を実現しました。安全性も重視し、刺激性のあるエッセンシャルオイルを扱う際にはラテックス手袋を着用するなどの対策講行了されました。レシピは個人のかぶれやすさや感度に合わせて調整され、カフェインが省略され、クエン酸と人工甘味料(当初はナトリウムシклаマートとサッカリンで 1:8 の希釈比、後に「Syntez-Cola」バージョンではスクラロースとバニリン)を使用しています。一部のロットでは若干の苦みが残る事例もありました。さらに、血橙、ライム、アーモンド油によるアルモンド風味のドリンク(マザパンのようなニュアンスを持つものも)などの追加作品も作成されました。実用的な課題として、ハンドミキサー由来のプラスチックのカスを濾し取ることや、ガラス製または金属製の容器の利用が検討されました。著者は自家製コーラをデカフェ Coca-Cola より優れていると評価しており、「味が薄い」と述べています。レシピバージョンは記録されており(例:blinry orange 0.1.1、blinry almond 0.1.1 など)、2026 年には Open Soda のウェブサイトが閉鎖された後、プロジェクトは新ブログと Git リポジトリを通じた詳細な変更ログやバージョニングされた配合を公開する透明性の高いデジタルリソースへと進化しました。このイニシアチブは、趣味家のための再現性のあるレシピや、ダイエットに意識的な消費者のための高度な炭酸飲料(スーパーマーケットの標準品にはない独自の風味プロファイルを備えたもの)を提供します。