コンテンツにスキップ

利用者:Ef3/Hypot

出典: フリー教科書『ウィキブックス(Wikibooks)』
hypot.go
package main

import (
	"fmt"
	"math"
)

// SimpleHypot は単純な実装
func simpleHypot(x, y float64) float64 {
	return math.Sqrt(x*x + y*y)
}

// 改善されたhypot実装
func hypot(x, y float64) float64 {
	getHighWord := func(f float64) int32 {
		return int32(math.Float64bits(f) >> 32)
	}

	getLowWord := func(f float64) int32 {
		return int32(math.Float64bits(f))
	}

	setHighWord := func(f *float64, hw int32) {
		bits := math.Float64bits(*f)
		*f = math.Float64frombits(uint64(hw)<<32 | uint64(bits&0xFFFFFFFF))
	}

	ha := getHighWord(x) & 0x7fffffff
	hb := getHighWord(y) & 0x7fffffff

	a, b := x, y
	if hb > ha {
		a, b = y, x
		ha, hb = hb, ha
	}

	a = math.Abs(a)
	b = math.Abs(b)

	if ha-hb > 0x3c00000 {
		return a + b
	}

	k := 0
	if ha > 0x5f300000 {
		if ha >= 0x7ff00000 {
			w := math.Abs(x+0.0) - math.Abs(y+0.0)
			low := getLowWord(a)
			if (ha&0xfffff | low) == 0 {
				w = a
			}
			low = getLowWord(b)
			if (hb ^ 0x7ff00000 | low) == 0 {
				w = b
			}
			return w
		}
		ha -= 0x25800000
		hb -= 0x25800000
		k += 600
		setHighWord(&a, ha)
		setHighWord(&b, hb)
	}

	if hb < 0x20b00000 {
		if hb <= 0x000fffff {
			low := getLowWord(b)
			if (hb | low) == 0 {
				return a
			}
			t1 := 0.0
			setHighWord(&t1, 0x7fd00000)
			b *= t1
			a *= t1
			k -= 1022
		} else {
			ha += 0x25800000
			hb += 0x25800000
			k -= 600
			setHighWord(&a, ha)
			setHighWord(&b, hb)
		}
	}

	w := a - b
	if w > b {
		t1 := 0.0
		setHighWord(&t1, ha)
		t2 := a - t1
		w = math.Sqrt(t1*t1 - (b*(-b) - t2*(a+t1)))
	} else {
		a = a + a
		y1 := 0.0
		setHighWord(&y1, hb)
		y2 := b - y1
		t1 := 0.0
		setHighWord(&t1, ha+0x00100000)
		t2 := a - t1
		w = math.Sqrt(t1*y1 - (w*(-w) - (t1*y2 + t2*b)))
	}

	if k != 0 {
		t1 := 0.0
		setHighWord(&t1, int32((1023+k)<<20))
		return t1 * w
	}
	return w
}

// 比較関数
func compareResults(x, y float64) {
	h1 := hypot(x, y)
	h2 := simpleHypot(x, y)
	h3 := math.Hypot(x, y)

	fmt.Printf("\nTest case: x=%.22g, y=%.22g\n", x, y)
	fmt.Printf("Custom hypot:     %.22g\n", h1)
	fmt.Printf("Simple hypot:     %.22g\n", h2)
	fmt.Printf("Standard hypot:   %.22g\n", h3)

	// NaNチェックを含む比較
	if math.IsNaN(h1) || math.IsNaN(h2) || math.IsNaN(h3) {
		fmt.Printf("NaN検出!\n")
		fmt.Printf("Custom IsNaN:   %v\n", math.IsNaN(h1))
		fmt.Printf("Simple IsNaN:   %v\n", math.IsNaN(h2))
		fmt.Printf("Standard IsNaN: %v\n", math.IsNaN(h3))
		return
	}

	// 結果が異なる場合の相対誤差計算
	if h1 != h2 || h1 != h3 {
		fmt.Printf("差異検出!\n")
		if !math.IsInf(h1, 0) && !math.IsInf(h2, 0) {
			relErr12 := math.Abs(h1-h2) / math.Max(math.Abs(h1), math.Abs(h2))
			fmt.Printf("Custom vs Simple 相対誤差: %g\n", relErr12)
		} else {
			fmt.Printf("Custom vs Simple: 少なくとも1つが無限大\n")
		}

		if !math.IsInf(h1, 0) && !math.IsInf(h3, 0) {
			relErr13 := math.Abs(h1-h3) / math.Max(math.Abs(h1), math.Abs(h3))
			fmt.Printf("Custom vs Standard 相対誤差: %g\n", relErr13)
		} else {
			fmt.Printf("Custom vs Standard: 少なくとも1つが無限大\n")
		}
	}
}

func main() {
	fmt.Println("=== 通常のケース ===")
	compareResults(3, 4)
	compareResults(1e-8, 1e-8)

	fmt.Println("\n=== 極端な値のケース ===")
	compareResults(1e300, 1e300)
	compareResults(1e-300, 1e-300)

	fmt.Println("\n=== 非常に異なる大きさの値 ===")
	compareResults(1e308, 1e-308)
	compareResults(1e50, 1e-50)

	fmt.Println("\n=== 特殊な値 ===")
	compareResults(math.Inf(1), 1.0)
	compareResults(math.NaN(), 1.0)
	compareResults(0.0, 0.0)

	fmt.Println("\n=== オーバーフローが起こりやすいケース ===")
	compareResults(1e308, 1e308)
	compareResults(math.MaxFloat64/2, math.MaxFloat64/2)

	fmt.Println("\n=== アンダーフローが起こりやすいケース ===")
	compareResults(math.SmallestNonzeroFloat64, math.SmallestNonzeroFloat64)
	compareResults(1e-308, 1e-308)
}
hypot.js
// IEEE 754 Float64用のhypot実装
function hypot(x, y) {
    // Float64のビット操作ヘルパー
    function getHighWord(f) {
        // Float64ArrayとUint32Arrayで上位32ビットを取得
        const float64 = new Float64Array(1);
        float64[0] = f;
        const uint32 = new Uint32Array(float64.buffer);
        // JavaScriptはリトルエンディアンが一般的なので、インデックス1を使用
        return uint32[1];
    }

    function getLowWord(f) {
        const float64 = new Float64Array(1);
        float64[0] = f;
        const uint32 = new Uint32Array(float64.buffer);
        return uint32[0];
    }

    function setHighWord(f, hw) {
        const float64 = new Float64Array(1);
        float64[0] = f;
        const uint32 = new Uint32Array(float64.buffer);
        uint32[1] = hw;
        return float64[0];
    }

    let ha = getHighWord(x) & 0x7fffffff;
    let hb = getHighWord(y) & 0x7fffffff;

    let a, b;
    if (hb > ha) {
        [a, b] = [y, x];
        [ha, hb] = [hb, ha];
    } else {
        [a, b] = [x, y];
    }

    a = Math.abs(a);
    b = Math.abs(b);

    if (ha - hb > 0x3c00000) {
        return a + b;
    }

    let k = 0;
    if (ha > 0x5f300000) {
        if (ha >= 0x7ff00000) {
            const w = Math.abs(x + 0.0) - Math.abs(y + 0.0);
            const low = getLowWord(a);
            if ((ha & 0xfffff | low) === 0) {
                return a;
            }
            if ((hb ^ 0x7ff00000 | getLowWord(b)) === 0) {
                return b;
            }
            return w;
        }
        ha -= 0x25800000;
        hb -= 0x25800000;
        k += 600;
        a = setHighWord(a, ha);
        b = setHighWord(b, hb);
    }

    if (hb < 0x20b00000) {
        if (hb <= 0x000fffff) {
            const low = getLowWord(b);
            if ((hb | low) === 0) {
                return a;
            }
            let t1 = setHighWord(0, 0x7fd00000);
            b *= t1;
            a *= t1;
            k -= 1022;
        } else {
            ha += 0x25800000;
            hb += 0x25800000;
            k -= 600;
            a = setHighWord(a, ha);
            b = setHighWord(b, hb);
        }
    }

    let w = a - b;
    if (w > b) {
        const t1 = setHighWord(0, ha);
        const t2 = a - t1;
        w = Math.sqrt(t1 * t1 - (b * (-b) - t2 * (a + t1)));
    } else {
        a = a + a;
        const y1 = setHighWord(0, hb);
        const y2 = b - y1;
        const t1 = setHighWord(0, ha + 0x00100000);
        const t2 = a - t1;
        w = Math.sqrt(t1 * y1 - (w * (-w) - (t1 * y2 + t2 * b)));
    }

    if (k !== 0) {
        const t1 = setHighWord(0, (1023 + k) << 20);
        return t1 * w;
    }
    return w;
}

// テストコード
function compareResults(x, y) {
    const h1 = hypot(x, y);
    const h2 = Math.sqrt(x * x + y * y);
    const h3 = Math.hypot(x, y);

    console.log(`\nTest case: x=${x.toPrecision(17)}, y=${y.toPrecision(17)}`);
    console.log(`Custom hypot:     ${h1.toPrecision(17)}`);
    console.log(`Simple hypot:     ${h2.toPrecision(17)}`);
    console.log(`Standard hypot:   ${h3.toPrecision(17)}`);

    // NaNチェック
    if (Number.isNaN(h1) || Number.isNaN(h2) || Number.isNaN(h3)) {
        console.log("NaN検出!");
        console.log(`Custom IsNaN:   ${Number.isNaN(h1)}`);
        console.log(`Simple IsNaN:   ${Number.isNaN(h2)}`);
        console.log(`Standard IsNaN: ${Number.isNaN(h3)}`);
        return;
    }

    // 結果比較
    if (h1 !== h2 || h1 !== h3) {
        console.log("差異検出!");
        if (!Number.isFinite(h1) || !Number.isFinite(h2)) {
            console.log("Custom vs Simple: 少なくとも1つが無限大");
        } else {
            const relErr12 = Math.abs(h1 - h2) / Math.max(Math.abs(h1), Math.abs(h2));
            console.log(`Custom vs Simple 相対誤差: ${relErr12.toPrecision(17)}`);
        }

        if (!Number.isFinite(h1) || !Number.isFinite(h3)) {
            console.log("Custom vs Standard: 少なくとも1つが無限大");
        } else {
            const relErr13 = Math.abs(h1 - h3) / Math.max(Math.abs(h1), Math.abs(h3));
            console.log(`Custom vs Standard 相対誤差: ${relErr13.toPrecision(17)}`);
        }
    }
}

// テストの実行
console.log("=== 通常のケース ===");
compareResults(3, 4);
compareResults(1e-8, 1e-8);

console.log("\n=== 極端な値のケース ===");
compareResults(1e300, 1e300);
compareResults(1e-300, 1e-300);

console.log("\n=== 非常に異なる大きさの値 ===");
compareResults(1e308, 1e-308);
compareResults(1e50, 1e-50);

console.log("\n=== 特殊な値 ===");
compareResults(Infinity, 1.0);
compareResults(NaN, 1.0);
compareResults(0.0, 0.0);

console.log("\n=== オーバーフローが起こりやすいケース ===");
compareResults(1e308, 1e308);
compareResults(Number.MAX_VALUE/2, Number.MAX_VALUE/2);

console.log("\n=== アンダーフローが起こりやすいケース ===");
compareResults(Number.MIN_VALUE, Number.MIN_VALUE);
compareResults(1e-308, 1e-308);
hypot.rs
use std::f64::{self, INFINITY, NAN};

// 単純な実装
fn simple_hypot(x: f64, y: f64) -> f64 {
    (x * x + y * y).sqrt()
}

// 改善された実装
fn hypot(mut x: f64, mut y: f64) -> f64 {
    // ビット操作のためのヘルパー関数
    fn get_high_word(f: f64) -> i32 {
        (f.to_bits() >> 32) as i32
    }

    fn get_low_word(f: f64) -> i32 {
        f.to_bits() as i32
    }

    fn set_high_word(f: &mut f64, hw: i32) {
        let bits = f.to_bits();
        *f = f64::from_bits((hw as u64) << 32 | (bits & 0xFFFFFFFF));
    }

    let mut ha = get_high_word(x) & 0x7fffffff;
    let mut hb = get_high_word(y) & 0x7fffffff;
    
    let mut a = x;
    let mut b = y;

    if hb > ha {
        std::mem::swap(&mut a, &mut b);
        std::mem::swap(&mut ha, &mut hb);
    }

    a = a.abs();
    b = b.abs();

    if ha - hb > 0x3c00000 {
        return a + b;
    }

    let mut k = 0;
    if ha > 0x5f300000 {
        if ha >= 0x7ff00000 {
            let w = (x + 0.0).abs() - (y + 0.0).abs();
            let low = get_low_word(a);
            if (ha & 0xfffff | low) == 0 {
                return a;
            }
            let low = get_low_word(b);
            if (hb ^ 0x7ff00000 | low) == 0 {
                return b;
            }
            return w;
        }
        ha -= 0x25800000;
        hb -= 0x25800000;
        k += 600;
        set_high_word(&mut a, ha);
        set_high_word(&mut b, hb);
    }

    if hb < 0x20b00000 {
        if hb <= 0x000fffff {
            let low = get_low_word(b);
            if (hb | low) == 0 {
                return a;
            }
            let mut t1 = 0.0;
            set_high_word(&mut t1, 0x7fd00000);
            b *= t1;
            a *= t1;
            k -= 1022;
        } else {
            ha += 0x25800000;
            hb += 0x25800000;
            k -= 600;
            set_high_word(&mut a, ha);
            set_high_word(&mut b, hb);
        }
    }

    let w = a - b;
    if w > b {
        let mut t1 = 0.0;
        set_high_word(&mut t1, ha);
        let t2 = a - t1;
        let w = ((t1 * t1) - (b * (-b) - t2 * (a + t1))).sqrt();
        if k != 0 {
            let mut t1 = 0.0;
            set_high_word(&mut t1, ((1023 + k) << 20) as i32);
            return t1 * w;
        }
        return w;
    } else {
        a = a + a;
        let mut y1 = 0.0;
        set_high_word(&mut y1, hb);
        let y2 = b - y1;
        let mut t1 = 0.0;
        set_high_word(&mut t1, ha + 0x00100000);
        let t2 = a - t1;
        let w = ((t1 * y1) - (w * (-w) - (t1 * y2 + t2 * b))).sqrt();
        if k != 0 {
            let mut t1 = 0.0;
            set_high_word(&mut t1, ((1023 + k) << 20) as i32);
            return t1 * w;
        }
        return w;
    }
}

fn compare_results(x: f64, y: f64) {
    let h1 = hypot(x, y);
    let h2 = simple_hypot(x, y);
    let h3 = f64::hypot(x, y);

    println!("\nTest case: x={:e}, y={:e}", x, y);
    println!("Custom hypot:     {:e}", h1);
    println!("Simple hypot:     {:e}", h2);
    println!("Standard hypot:   {:e}", h3);

    // NaNチェック
    if h1.is_nan() || h2.is_nan() || h3.is_nan() {
        println!("NaN検出!");
        println!("Custom IsNaN:   {}", h1.is_nan());
        println!("Simple IsNaN:   {}", h2.is_nan());
        println!("Standard IsNaN: {}", h3.is_nan());
        return;
    }

    // 結果が異なる場合の相対誤差計算
    if h1 != h2 || h1 != h3 {
        println!("差異検出!");
        if !h1.is_infinite() && !h2.is_infinite() {
            let rel_err12 = (h1 - h2).abs() / h1.abs().max(h2.abs());
            println!("Custom vs Simple 相対誤差: {:e}", rel_err12);
        } else {
            println!("Custom vs Simple: 少なくとも1つが無限大");
        }
        if !h1.is_infinite() && !h3.is_infinite() {
            let rel_err13 = (h1 - h3).abs() / h1.abs().max(h3.abs());
            println!("Custom vs Standard 相対誤差: {:e}", rel_err13);
        } else {
            println!("Custom vs Standard: 少なくとも1つが無限大");
        }
    }
}

fn main() {
    println!("=== 通常のケース ===");
    compare_results(3.0, 4.0);
    compare_results(1e-8, 1e-8);

    println!("\n=== 極端な値のケース ===");
    compare_results(1e300, 1e300);
    compare_results(1e-300, 1e-300);

    println!("\n=== 非常に異なる大きさの値 ===");
    compare_results(1e308, 1e-308);
    compare_results(1e50, 1e-50);

    println!("\n=== 特殊な値 ===");
    compare_results(INFINITY, 1.0);
    compare_results(NAN, 1.0);
    compare_results(0.0, 0.0);

    println!("\n=== オーバーフローが起こりやすいケース ===");
    compare_results(1e308, 1e308);
    compare_results(f64::MAX/2.0, f64::MAX/2.0);

    println!("\n=== アンダーフローが起こりやすいケース ===");
    compare_results(f64::MIN_POSITIVE, f64::MIN_POSITIVE);
    compare_results(1e-308, 1e-308);
}
hypot.c++
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdint>
#include <iomanip>

// ビット操作のためのユーティリティ関数
union DoubleBits {
    double d;
    uint64_t bits;
};

int32_t getHighWord(double f) {
    DoubleBits db{f};
    return static_cast<int32_t>(db.bits >> 32);
}

int32_t getLowWord(double f) {
    DoubleBits db{f};
    return static_cast<int32_t>(db.bits & 0xFFFFFFFF);
}

void setHighWord(double& f, int32_t hw) {
    DoubleBits db{f};
    db.bits = (static_cast<uint64_t>(hw) << 32) | (db.bits & 0xFFFFFFFF);
    f = db.d;
}

// 単純な実装
double simpleHypot(double x, double y) {
    return std::sqrt(x * x + y * y);
}

// 改善された実装
double hypot(double x, double y) {
    int32_t ha = getHighWord(x) & 0x7fffffff;
    int32_t hb = getHighWord(y) & 0x7fffffff;
    
    double a = x;
    double b = y;

    if (hb > ha) {
        std::swap(a, b);
        std::swap(ha, hb);
    }

    a = std::abs(a);
    b = std::abs(b);

    if (ha - hb > 0x3c00000) {
        return a + b;
    }

    int k = 0;
    if (ha > 0x5f300000) {
        if (ha >= 0x7ff00000) {
            double w = std::abs(x + 0.0) - std::abs(y + 0.0);
            int32_t low = getLowWord(a);
            if ((ha & 0xfffff | low) == 0) {
                return a;
            }
            low = getLowWord(b);
            if ((hb ^ 0x7ff00000 | low) == 0) {
                return b;
            }
            return w;
        }
        ha -= 0x25800000;
        hb -= 0x25800000;
        k += 600;
        setHighWord(a, ha);
        setHighWord(b, hb);
    }

    if (hb < 0x20b00000) {
        if (hb <= 0x000fffff) {
            int32_t low = getLowWord(b);
            if ((hb | low) == 0) {
                return a;
            }
            double t1 = 0.0;
            setHighWord(t1, 0x7fd00000);
            b *= t1;
            a *= t1;
            k -= 1022;
        } else {
            ha += 0x25800000;
            hb += 0x25800000;
            k -= 600;
            setHighWord(a, ha);
            setHighWord(b, hb);
        }
    }

    double w = a - b;
    if (w > b) {
        double t1 = 0.0;
        setHighWord(t1, ha);
        double t2 = a - t1;
        w = std::sqrt(t1 * t1 - (b * (-b) - t2 * (a + t1)));
        if (k != 0) {
            double t1 = 0.0;
            setHighWord(t1, (1023 + k) << 20);
            return t1 * w;
        }
        return w;
    } else {
        a = a + a;
        double y1 = 0.0;
        setHighWord(y1, hb);
        double y2 = b - y1;
        double t1 = 0.0;
        setHighWord(t1, ha + 0x00100000);
        double t2 = a - t1;
        w = std::sqrt(t1 * y1 - (w * (-w) - (t1 * y2 + t2 * b)));
        if (k != 0) {
            double t1 = 0.0;
            setHighWord(t1, (1023 + k) << 20);
            return t1 * w;
        }
        return w;
    }
}

void compareResults(double x, double y) {
    double h1 = hypot(x, y);
    double h2 = simpleHypot(x, y);
    double h3 = std::hypot(x, y);

    std::cout << std::scientific << std::setprecision(20);
    std::cout << "\nTest case: x=" << x << ", y=" << y << std::endl;
    std::cout << "Custom hypot:     " << h1 << std::endl;
    std::cout << "Simple hypot:     " << h2 << std::endl;
    std::cout << "Standard hypot:   " << h3 << std::endl;

    // NaNチェック
    if (std::isnan(h1) || std::isnan(h2) || std::isnan(h3)) {
        std::cout << "NaN検出!" << std::endl;
        std::cout << "Custom IsNaN:   " << std::isnan(h1) << std::endl;
        std::cout << "Simple IsNaN:   " << std::isnan(h2) << std::endl;
        std::cout << "Standard IsNaN: " << std::isnan(h3) << std::endl;
        return;
    }

    // 結果が異なる場合の相対誤差計算
    if (h1 != h2 || h1 != h3) {
        std::cout << "差異検出!" << std::endl;
        if (!std::isinf(h1) && !std::isinf(h2)) {
            double relErr12 = std::abs(h1 - h2) / std::max(std::abs(h1), std::abs(h2));
            std::cout << "Custom vs Simple 相対誤差: " << relErr12 << std::endl;
        } else {
            std::cout << "Custom vs Simple: 少なくとも1つが無限大" << std::endl;
        }
        if (!std::isinf(h1) && !std::isinf(h3)) {
            double relErr13 = std::abs(h1 - h3) / std::max(std::abs(h1), std::abs(h3));
            std::cout << "Custom vs Standard 相対誤差: " << relErr13 << std::endl;
        } else {
            std::cout << "Custom vs Standard: 少なくとも1つが無限大" << std::endl;
        }
    }
}

int main() {
    std::cout << "=== 通常のケース ===" << std::endl;
    compareResults(3.0, 4.0);
    compareResults(1e-8, 1e-8);

    std::cout << "\n=== 極端な値のケース ===" << std::endl;
    compareResults(1e300, 1e300);
    compareResults(1e-300, 1e-300);

    std::cout << "\n=== 非常に異なる大きさの値 ===" << std::endl;
    compareResults(1e308, 1e-308);
    compareResults(1e50, 1e-50);

    std::cout << "\n=== 特殊な値 ===" << std::endl;
    compareResults(INFINITY, 1.0);
    compareResults(NAN, 1.0);
    compareResults(0.0, 0.0);

    std::cout << "\n=== オーバーフローが起こりやすいケース ===" << std::endl;
    compareResults(1e308, 1e308);
    compareResults(std::numeric_limits<double>::max()/2.0, 
                  std::numeric_limits<double>::max()/2.0);

    std::cout << "\n=== アンダーフローが起こりやすいケース ===" << std::endl;
    compareResults(std::numeric_limits<double>::min(), 
                  std::numeric_limits<double>::min());
    compareResults(1e-308, 1e-308);

    return 0;
}
hypot.py
import math
import struct

# ビット操作のためのヘルパー関数
def get_high_word(f: float) -> int:
    bits = struct.unpack('Q', struct.pack('d', f))[0]
    return (bits >> 32) & 0xFFFFFFFF

def get_low_word(f: float) -> int:
    bits = struct.unpack('Q', struct.pack('d', f))[0]
    return bits & 0xFFFFFFFF

def set_high_word(f: float, hw: int) -> float:
    bits = struct.unpack('Q', struct.pack('d', f))[0]
    bits = (bits & 0xFFFFFFFF) | ((hw & 0xFFFFFFFF) << 32)
    return struct.unpack('d', struct.pack('Q', bits))[0]

# 単純な実装
def simple_hypot(x: float, y: float) -> float:
    return math.sqrt(x * x + y * y)

# 改善された実装
def hypot(x: float, y: float) -> float:
    ha = get_high_word(x) & 0x7fffffff
    hb = get_high_word(y) & 0x7fffffff
    
    if hb > ha:
        x, y = y, x
        ha, hb = hb, ha
    
    a = abs(x)
    b = abs(y)
    
    if ha - hb > 0x3c00000:
        return a + b
    
    k = 0
    if ha > 0x5f300000:
        if ha >= 0x7ff00000:
            w = abs(x + 0.0) - abs(y + 0.0)
            low = get_low_word(a)
            if (ha & 0xfffff | low) == 0:
                return a
            low = get_low_word(b)
            if (hb ^ 0x7ff00000 | low) == 0:
                return b
            return w
        ha -= 0x25800000
        hb -= 0x25800000
        k += 600
        a = set_high_word(a, ha)
        b = set_high_word(b, hb)
    
    if hb < 0x20b00000:
        if hb <= 0x000fffff:
            low = get_low_word(b)
            if (hb | low) == 0:
                return a
            t1 = set_high_word(0.0, 0x7fd00000)
            b *= t1
            a *= t1
            k -= 1022
        else:
            ha += 0x25800000
            hb += 0x25800000
            k -= 600
            a = set_high_word(a, ha)
            b = set_high_word(b, hb)
    
    w = a - b
    if w > b:
        t1 = set_high_word(0.0, ha)
        t2 = a - t1
        w = math.sqrt(t1 * t1 - (b * (-b) - t2 * (a + t1)))
        if k != 0:
            return set_high_word(0.0, ((1023 + k) << 20)) * w
        return w
    else:
        a = a + a
        y1 = set_high_word(0.0, hb)
        y2 = b - y1
        t1 = set_high_word(0.0, ha + 0x00100000)
        t2 = a - t1
        w = math.sqrt(t1 * y1 - (w * (-w) - (t1 * y2 + t2 * b)))
        if k != 0:
            return set_high_word(0.0, ((1023 + k) << 20)) * w
        return w

def compare_results(x: float, y: float) -> None:
    h1 = hypot(x, y)
    h2 = simple_hypot(x, y)
    h3 = math.hypot(x, y)
    
    print(f"\nTest case: x={x:e}, y={y:e}")
    print(f"Custom hypot:     {h1:e}")
    print(f"Simple hypot:     {h2:e}")
    print(f"Standard hypot:   {h3:e}")
    
    # NaNチェック
    if math.isnan(h1) or math.isnan(h2) or math.isnan(h3):
        print("NaN検出!")
        print(f"Custom IsNaN:   {math.isnan(h1)}")
        print(f"Simple IsNaN:   {math.isnan(h2)}")
        print(f"Standard IsNaN: {math.isnan(h3)}")
        return
    
    # 結果が異なる場合の相対誤差計算
    if h1 != h2 or h1 != h3:
        print("差異検出!")
        if not math.isinf(h1) and not math.isinf(h2):
            rel_err12 = abs(h1 - h2) / max(abs(h1), abs(h2))
            print(f"Custom vs Simple 相対誤差: {rel_err12:e}")
        else:
            print("Custom vs Simple: 少なくとも1つが無限大")
        if not math.isinf(h1) and not math.isinf(h3):
            rel_err13 = abs(h1 - h3) / max(abs(h1), abs(h3))
            print(f"Custom vs Standard 相対誤差: {rel_err13:e}")
        else:
            print("Custom vs Standard: 少なくとも1つが無限大")

def main():
    print("=== 通常のケース ===")
    compare_results(3.0, 4.0)
    compare_results(1e-8, 1e-8)
    
    print("\n=== 極端な値のケース ===")
    compare_results(1e300, 1e300)
    compare_results(1e-300, 1e-300)
    
    print("\n=== 非常に異なる大きさの値 ===")
    compare_results(1e308, 1e-308)
    compare_results(1e50, 1e-50)
    
    print("\n=== 特殊な値 ===")
    compare_results(float('inf'), 1.0)
    compare_results(float('nan'), 1.0)
    compare_results(0.0, 0.0)
    
    print("\n=== オーバーフローが起こりやすいケース ===")
    compare_results(1e308, 1e308)
    compare_results(float('inf')/2, float('inf')/2)
    
    print("\n=== アンダーフローが起こりやすいケース ===")
    compare_results(2.2250738585072014e-308, 2.2250738585072014e-308)  # min positive
    compare_results(1e-308, 1e-308)

if __name__ == "__main__":
    main()
hypot_time.py
import math
import struct
import timeit

# ビット操作のためのヘルパー関数
def get_high_word(f: float) -> int:
    bits = struct.unpack('Q', struct.pack('d', f))[0]
    return (bits >> 32) & 0xFFFFFFFF

def set_high_word(f: float, hw: int) -> float:
    bits = struct.unpack('Q', struct.pack('d', f))[0]
    bits = (bits & 0xFFFFFFFF) | ((hw & 0xFFFFFFFF) << 32)
    return struct.unpack('d', struct.pack('Q', bits))[0]

# 単純な実装
def simple_hypot(x: float, y: float) -> float:
    return math.sqrt(x * x + y * y)

# 改善された実装
def hypot(x: float, y: float) -> float:
    ha = get_high_word(x) & 0x7fffffff
    hb = get_high_word(y) & 0x7fffffff
    
    if hb > ha:
        x, y = y, x
        ha, hb = hb, ha
    
    a = abs(x)
    b = abs(y)
    
    if ha - hb > 0x3c00000:
        return a + b
    
    k = 0
    if ha > 0x5f300000:
        if ha >= 0x7ff00000:
            w = abs(x + 0.0) - abs(y + 0.0)
            if (ha & 0xfffff | get_high_word(a) & 0xffffffff) == 0:
                return a
            if (hb ^ 0x7ff00000 | get_high_word(b) & 0xffffffff) == 0:
                return b
            return w
        ha -= 0x25800000
        hb -= 0x25800000
        k += 600
        a = set_high_word(a, ha)
        b = set_high_word(b, hb)
    
    if hb < 0x20b00000:
        if hb <= 0x000fffff:
            if hb == 0 and get_high_word(b) == 0:
                return a
            t1 = set_high_word(0.0, 0x7fd00000)
            b *= t1
            a *= t1
            k -= 1022
        else:
            ha += 0x25800000
            hb += 0x25800000
            k -= 600
            a = set_high_word(a, ha)
            b = set_high_word(b, hb)
    
    w = a - b
    if w > b:
        t1 = set_high_word(0.0, ha)
        t2 = a - t1
        w = math.sqrt(t1 * t1 - (b * (-b) - t2 * (a + t1)))
        if k != 0:
            return set_high_word(0.0, ((1023 + k) << 20)) * w
        return w
    else:
        a = a + a
        y1 = set_high_word(0.0, hb)
        y2 = b - y1
        t1 = set_high_word(0.0, ha + 0x00100000)
        t2 = a - t1
        w = math.sqrt(t1 * y1 - (w * (-w) - (t1 * y2 + t2 * b)))
        if k != 0:
            return set_high_word(0.0, ((1023 + k) << 20)) * w
        return w

# パフォーマンス比較関数
def performance_comparison():
    test_cases = [
        (3.0, 4.0),
        (1e-8, 1e-8),
        (1e300, 1e300),
        (1e-300, 1e-300),
        (1e308, 1e-308),
        (float('inf'), 1.0),
        (0.0, 0.0)
    ]

    print("=== パフォーマンス測定結果 ===")
    for x, y in test_cases:
        print(f"\nTest case: x={x:e}, y={y:e}")
        
        # 時間計測
        time_custom = timeit.timeit(lambda: hypot(x, y), number=100000)
        time_simple = timeit.timeit(lambda: simple_hypot(x, y), number=100000)
        time_standard = timeit.timeit(lambda: math.hypot(x, y), number=100000)
        
        print(f"Custom hypot:   {time_custom:.6f} 秒")
        print(f"Simple hypot:   {time_simple:.6f} 秒")
        print(f"Standard hypot: {time_standard:.6f} 秒")

# 実行
if __name__ == "__main__":
    performance_comparison()
hypot.js
hypot.js