<?xml version="1.0" encoding="utf-8" ?>
<feed version="0.3"
	xml:lang="ja"
	xmlns="http://purl.org/atom/ns#"
	xmlns:dc="http://purl.org/dc/elements/1.1/">
	<title>Hundredsoft</title>
	<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/" />
	<modified>2011-12-08T13:54:41+00:00</modified>
	<tagline><![CDATA[]]></tagline>
	<generator url="http://serenebach.net/">Serene Bach</generator>
	<entry>
		<title>ニュートン法を使った２進多桁の整数除算(その２)</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid99.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid99.html</id>
		<issued>2011-02-20T08:56:30+09:00</issued>
		<modified>2011-02-19T23:56:30Z</modified>
		<summary>前回、除算 x = p / q　をNewton法を使って解くプログラムを紹介しましたが、単独の初期値を使った方法では、あまり早くありません。数万bitを超える多桁演算の場合、64bit精度の初期値を使ったとしても、あまり速...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[<a href="http://www.hundredsoft.jp/win7blog/log/eid94.html" target="_self" title="Newton法除算">前回、</a>除算 x = p / q　をNewton法を使って解くプログラムを紹介しましたが、<br />
単独の初期値を使った方法では、あまり早くありません。<br />
数万bitを超える多桁演算の場合、64bit精度の初期値を使ったとしても、あまり速度に差が出ません。<br />
そこで大きな桁(数万bitを超える)で計算を開始するのではなく、除数(q)の先頭部分を使った小さな桁で計算を開始して、これをNewton法の初期値とし、もう少し大きな桁でNewton法を解く、<br />
これを繰り返して最終的な答えを得る方法を紹介します。<br />
<em>少しコード修正しました(2011.2.11)</em>
<br />

<blockquote><pre><code><xmp>
Bigint newtondiv(const Bigint&amp; q, const int&amp; n, const Bigint&amp; init){
  Bigint x(init), m(0), c2(2);
  c2 <<= n;
  while(m != x){
    m = x;
    x *= c2 - q * x;
    x >>= n;
  }
  return x;
}

Bigint iDiv(Bigint p, Bigint q){
  int pb = p.length(); // 被除数のbit数
  int qb = q.length(); // 除数のbit数
  int n;
  int b = 64;
  int step = qb / 4;

  Bigint d = 1;
  d <<= b;      // Newton法の初期値として, 1 << b を与える。

  d = newtondiv(q >> (qb-b), b*2, d);  // 1回目
  b += step;
  d <<= step;

  d = newtondiv(q >> (qb-b), b*2, d);  // 2回目
  b += step;
  d <<= step;

  d = newtondiv(q >> (qb-b), b*2, d);  // 3回目
  d <<= (pb-b);
  n = pb + qb;

  d = newtondiv(q, n, d);  // 4回目

  d *= p;        // d = p / q
  d >>= n;

  // 誤差修正
  if (p >= (d+1)*q){
      d += 1;
  }
  return d;
}

</xmp></code></pre></blockquote>
<br />
newtondivは、Newton法で （2<sup>n</sup> / q） を求める関数です。<br />
初回は先頭64bit程度で計算します。<br />
2回目は、初回の計算結果を初期値として、64+(除数のBit数/4)での計算。<br />
3回目は、２回目の計算結果を初期値として、64+(除数のBit数/2)での計算。<br />
4回目は、３回目の計算結果を初期値として、全桁での計算。<br />
と計算桁を増やしていきます。<br />
<br />
除数・被除数のとり方にもよりますが、計算時間は明らかに短くなります。<br />
この方法は、Bigintの演算回数としては、効果はないのですが、<br />
可変長のFFT乗算を用いる場合、演算量は２の冪数桁単位に増加するので、<br />
Totalの計算量としては、こちらの方が有利です。<br />
<br />
4分割としていますが、利用するBigint(多倍長整数)クラスで最速となるよう調節する必要があります。<br />
これについては、<b>「高橋 大介, 金田 康正. "多倍長平方根の高速計算法". 情報処理学会研究報告 95-HPC-58, pp.51-56.」</b>が詳しいです。<br />
文献に従えば、初期値に倍精度結果を使う・３〜４分割程度・FFT再利用、を行えば最大限の高速化を望めますが、このサンプルコードではそこまで対応できていません。<br />
<br />
ここでは説明を簡単にするため初期値に（2^64）を与えています。<br />
より正確な初期値のとり方や、詳細アルゴリズムはこちら<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid99.html#sequel" target="_self">整数除算の詳細解説</a><br />
<br />
除数・非除数の桁差が小さければ、このような方法もあります。<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid91.html" target="_blank" title="回復法を使った２進多桁の除算">回復法を使った２進多桁の除算</a><br />
<br />
同様の計算方法を行っている、整数平方根解説はこちら<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid100.html#sequel" target="_self">整数平方根での詳細解説</a><br />
<br />
このアルゴリズムを利用した16進・２進・10進電卓です。<br />
整数だけですがおよそ100万桁まで計算できます。<br />
<a href="http://www.hundredsoft.jp/v16cal/" target="_blank"><img src="http://www.hundredsoft.jp/win7blog/img/v16cal.gif" title="v16cal" width="32" height="32" /></a>
<br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>
<br /><p><a href="http://www.hundredsoft.jp/win7blog/log/eid99.html#sequel">[続きがあります]</a></p>]]></content>
	</entry>
	<entry>
		<title>ニュートン法を使った２進多桁の整数平方根(その２)</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid100.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid100.html</id>
		<issued>2011-02-06T10:27:39+09:00</issued>
		<modified>2011-02-06T01:27:39Z</modified>
		<summary>前回、平方根 √s　をNewton法を使って解くプログラムを紹介しましたが、単独の初期値を使った方法では、あまり早くありません。数万bitを超える多桁演算の場合、64bit精度の初期値を使ったとしても、あまり速度に...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[<a href="http://www.hundredsoft.jp/win7blog/log/eid95.html" target="_self" title="Newton法平方根">前回、</a>平方根 √s　をNewton法を使って解くプログラムを紹介しましたが、<br />
単独の初期値を使った方法では、あまり早くありません。<br />
数万bitを超える多桁演算の場合、64bit精度の初期値を使ったとしても、あまり速度に差が出ません。<br />
そこで大きな桁(数万bitを超える)で計算を開始するのではなく、(s)の先頭部分を使った小さな桁で計算を開始して、これをNewton法の初期値とし、もう少し大きな桁でNewton法を解く、<br />
これを繰り返して最終的な答えを得る方法を紹介します。<br />
<br />

<blockquote><pre><code><xmp>
Bigint newtonsqrt(const Bigint&amp; q, const int&amp; n, const Bigint&amp; init){
  Bigint x(init), m(0), c3(3);
  c3 <<= n;
  while(m != x){
    m = x;
    x *= c3 - ((m * m * q) >> n);
    x >>= n+1;
  }
  return x;
}

Bigint iSqrt(Bigint s){
  int n = s.length(); // bit数
  int b;
  if (n &amp; 1)    b = 65; // 初期演算Bit数(n:奇数)
  else          b = 64; // 初期演算Bit数(n:偶数)

  Bigint x = 1;
  x <<= (b / 2);  // Newton法の初期値として, 1 << (b/2) を与える。

  Bigint w;
  int m = n / 8;  // 4分割程度

  while(1){
    w = s >> (n - b);        // (s)先頭から指定bit数(n-b)切り取り
    x = newtonsqrt(w, b, x);

    if (b + 2 * m > n)
      break;

    b += 2 * m;
    x <<= m;
  }
  x <<= (n - b) / 2;         // 必ず割り切れる
  x = newtonsqrt(s, n, x);

  x *= s;         // x = s * (2^n) / √s = (2^n) * √s
  x >>= n;        // x = √s

  // 誤差修正
  w = x + 1;
  if (s >= w * w){
     x = w;
  }
  return x;
}

</xmp></code></pre></blockquote>
<br />
newtonsqrtは、Newton法で （2<sup>n</sup> / √q） を求める関数です。<br />
初回は先頭64bit程度で計算します。<br />
2回目は、初回の計算結果を初期値として、(n/8)桁増やして計算。<br />
3回目は、２回目の計算結果を初期値として、更に(n/8)桁増やして計算。<br />
と次々と桁を増やしていきます。<br />
<br />
計算時間は明らかに短くなります。<br />
この方法は、Bigintの演算回数としては、効果はないのですが、<br />
可変長のFFT乗算を用いる場合、演算量は２の冪数桁単位に増加するので、<br />
Totalの計算量としては、こちらの方が有利です。<br />
<br />
分割数は、利用するBigint(多倍長整数)クラスで最速の性能が出るように調節する必要があります。<br />
これについては、<b>「高橋 大介, 金田 康正. "多倍長平方根の高速計算法". 情報処理学会研究報告 95-HPC-58, pp.51-56.」</b>が詳しいです。<br />
文献に従えば、初期値に倍精度結果を使う・３〜４分割程度・FFT再利用、を行えば最大限の高速化を望めますが、このサンプルコードではそこまで対応できていません。<br />
<br />
また、この方法は平方根に限らず、Newton法を使った様々な計算に応用できます。<br />
<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid100.html#sequel" target="_self">整数平方根での詳細解説</a>
<br />
<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid99.html#sequel" target="_self">整数除算での詳細解説</a>
<br />
<br />
このアルゴリズムを利用した16進・２進・10進電卓です。<br />
整数だけですがおよそ100万桁まで計算できます。<br />
<a href="http://www.hundredsoft.jp/v16cal/" target="_blank"><img src="http://www.hundredsoft.jp/win7blog/img/v16cal.gif" title="v16cal" width="32" height="32" /></a>
<br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>
<br /><p><a href="http://www.hundredsoft.jp/win7blog/log/eid100.html#sequel">[続きがあります]</a></p>]]></content>
	</entry>
	<entry>
		<title>モンゴメリ冪剰余 サンプルコード</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid98.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid98.html</id>
		<issued>2010-12-26T11:11:28+09:00</issued>
		<modified>2010-12-26T02:11:28Z</modified>
		<summary>前回、モンゴメリ乗算 サンプルコードを書きましたが、よく使われる冪剰余についてもC++サンプルを載せておきます。// モンゴメリ冪剰余演算 (a^b) mod nを求める// gcd(n,r) == 1 となること。(nは奇数であれば良...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[前回、<a href="http://www.hundredsoft.jp/win7blog/log/eid93.html" target="_blank" title="モンゴメリ乗算">モンゴメリ乗算 サンプルコード</a>を書きましたが、よく使われる冪剰余についてもC++サンプルを載せておきます。
<br />
<br />
<blockquote><pre><code><xmp>
// モンゴメリ冪剰余演算 (a^b) mod nを求める
// gcd(n,r) == 1 となること。(nは奇数であれば良い)
//
#ifndef MONTGOMERY_INCLUDED
#define MONTGOMERY_INCLUDED

#include "Bigint.h"

class montgomery{
public:
    montgomery(const Bigint&amp; n) : m_n(), m_r2(), m_nb(0), m_n2(){
        m_n = n;
        // n を法とする
        // Bit長を調べる(nb)
        m_nb = n.length();

        // r: nより大きな２のべき
        Bigint r(1);
        r <<= m_nb;

        // r2 = r^2 mod n
        m_r2 = r * r;
        m_r2 %= n;

        // n*n2 ≡ -1 mod r
        m_n2 = 0; /* 求めるN' */
        Bigint t = 0;
        Bigint vi = 1;
        int ni = m_nb;
        while (ni--){ /* Rのトップビットを除いたビット数分繰り返す */
            if ((t &amp; 1) == 0){
                /* ゼロになっているビットがあったら、N'のその部分を1にする（NはRと互いに素なので必ず奇数）*/
                t += n; /* 掛け算だが、二進数一桁の掛け算なので実質は足し算 */
                m_n2 += vi; /* N'のその部分を1にする */
            }
            t >>= 1; /* 必ず端数が出るが切り捨てる */
            vi <<= 1; /* Rは2の冪なので、絶対端数は出ない */
        }
    }

    ~montgomery(){}

    Bigint reduction(const Bigint&amp; t){
        // tのモンゴメリリダクション
        Bigint c = t * m_n2;
        c.hibitmask(m_nb); // mod Rの意味,(m_nb)bit以上を0クリア
        c *= m_n;
        c += t;
        c >>= m_nb; // 1/r の意味
        if (c >= m_n) c -= m_n;
        return c;
    }

    // 冪剰余 a^b mod n, バイナリ法の下位桁から計算
    Bigint exp(const Bigint&amp; a, const Bigint&amp; b){
        Bigint p = reduction(a * m_r2);
        Bigint x = reduction(m_r2);
        Bigint y(b);
        while (y > 0){
            if (y &amp; 1){
                x = reduction(x * p);
            }
            p = reduction(p * p);
            y >>= 1;
        }
        return reduction(x);
    }

protected:
    montgomery() : m_n(), m_r2(), m_nb(0), m_n2(){}

private:
    Bigint m_n;   // 法(m_n)
    Bigint m_r2;  // rを(m_n)より大きな２のべきとして、(m_r2)=(r)^2 mod n
    Bigint m_n2;  // (m_n)*(m_n2) ≡ -1 mod r を満たす(m_n2)
    int    m_nb;  // (m_n)の有効Bit数, 例えば(m_n)=5 のとき(m_nb)=3
};

#endif

</xmp></code></pre></blockquote>
<br />
<br />
<a href="http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%82%B4%E3%83%A1%E3%83%AA%E4%B9%97%E7%AE%97" target="_blank" title="モンゴメリ乗算">wikipedia</a>の説明にあるようにバイナリ法を用いています。<br />
初めに法(n)とするコンストラクタを呼び出します。<br />
冪剰余は、exp()メソッドで行います。<br />
<br />
<br />
このアルゴリズムを利用した16進・２進・10進電卓です。<br />
整数だけですがおよそ100万桁まで計算できます。<br />
<a href="http://www.hundredsoft.jp/v16cal/" target="_blank"><img src="http://www.hundredsoft.jp/win7blog/img/v16cal.gif" title="v16cal" width="32" height="32" /></a>
<br />
<br />
(注)Bigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>VC++で拡張倍精度をどうしても使いたい</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid97.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid97.html</id>
		<issued>2010-12-19T08:25:10+09:00</issued>
		<modified>2010-12-18T23:25:10Z</modified>
		<summary>VC++で拡張倍精度浮動小数点形式をどうしても使いたいVisual Stdioでは拡張倍精度浮動小数(80bit)が使えません。long double と書いても、64bit精度になります。通常、仮数部53bit(暗黙Bit含め)で不足することはな...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[VC++で拡張倍精度浮動小数点形式をどうしても使いたい<br />
<br />
Visual Stdioでは拡張倍精度浮動小数(80bit)が使えません。<br />
long double と書いても、64bit精度になります。<br />
通常、仮数部53bit(暗黙Bit含め)で不足することはないでしょうが、<br />
どうしても仮数部64bitが必要という場合のサンプルクラスです。<br />
様々なコンストラクタ、四則演算・比較の他、FPUでサポートしている三角関数や平方根を入れました。<br />
<br />

<blockquote><pre><code><xmp>
/* (c) Hundredsoft Corporation 2010 All rights reserved.

	Ldouble.h -  VC 拡張倍精度クラス

*/

#ifndef LDOUBLE_INCLUDED
#define LDOUBLE_INCLUDED

#include <memory.h>

typedef struct {
	unsigned char d[12];
} LONG_DOUBLE_STR, *LPLONG_DOUBLE_STR;

void Ldouble_init()
{
	unsigned short fcw=0x033f;	// round to nearest, 64 bits, exceptions disabled
	__asm {
		fldcw     [fcw]
	}
}

class Ldouble
{
public:
	Ldouble() {
		memset(&m_data, 0, sizeof(m_data));
	}
	virtual ~Ldouble(){}

	Ldouble(const Ldouble&amp; v) {
		if (this != &v){
			memcpy(&m_data, &v.m_data, sizeof(m_data));
		}
	}
	Ldouble(const __int64&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [v]
			fild qword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const unsigned __int64&amp; v) {
		__int64 t = 0x8000000000000000;
		int i;
		for (i=63; i>=0; i--, t>>=1){
			if (v &amp; t) break;
		}
		if (i < 0){
			memset(&m_data, 0, sizeof(m_data));
		}else{
			t = v;
			t <<= 63-i; // 仮数部
			int ex = i + 16383; // 指数部
			memcpy(&m_data, &t, sizeof(__int64));
			*(int*)&m_data.d[8] = ex;
		}
	}
	Ldouble(const int&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [v]
			fild dword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const unsigned int&amp; v) {
		__int64 i = v;
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			lea  eax, [i]
			fild qword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const short&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		int i = v;
		__asm {
			lea  eax, [i]
			fild dword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const unsigned short&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		int i = v;
		__asm {
			lea  eax, [i]
			fild dword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const char&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		int i = v;
		__asm {
			lea  eax, [i]
			fild dword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const unsigned char&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		int i = v;
		__asm {
			lea  eax, [i]
			fild dword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble(const double&amp; v) {
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [v]
			fld  qword ptr [eax]
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
	}
	Ldouble&amp; operator=(const Ldouble&amp; v){
		if (this != &v){
			memcpy(&m_data, &v.m_data, sizeof(m_data));
		}
		return *this;
	}

	// Unary -								
	Ldouble operator-(){
		Ldouble v = *this;
		v.m_data.d[9] ^= 0x80;
		return v;
	}
	Ldouble operator++(){
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fld1
			fadd
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return *this;
	}
	Ldouble operator++(int){
		Ldouble v = *this;
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fld1
			fadd
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return v;
	}
	Ldouble operator--(){
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fld1
			fsub
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return *this;
	}
	Ldouble operator--(int){
		Ldouble v = *this;
		LPLONG_DOUBLE_STR m = &m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fld1
			fsub
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return v;
	}

	// Binary operator +=, -=, *=, /=
	Ldouble&amp; operator+=(const Ldouble&amp; v){
		LPLONG_DOUBLE_STR m = &m_data;
		LPLONG_DOUBLE_STR mv = (LPLONG_DOUBLE_STR)&v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			mov  eax, [mv]
			fld  tbyte ptr [eax]
			fadd
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return *this;
	}
	Ldouble&amp; operator-=(const Ldouble&amp; v){
		LPLONG_DOUBLE_STR m = &m_data;
		LPLONG_DOUBLE_STR mv = (LPLONG_DOUBLE_STR)&v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			mov  eax, [mv]
			fld  tbyte ptr [eax]
			fsub
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return *this;
	}
	Ldouble&amp; operator*=(const Ldouble&amp; v){
		LPLONG_DOUBLE_STR m = &m_data;
		LPLONG_DOUBLE_STR mv = (LPLONG_DOUBLE_STR)&v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			mov  eax, [mv]
			fld  tbyte ptr [eax]
			fmul
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return *this;
	}
	Ldouble&amp; operator/=(const Ldouble&amp; v){
		LPLONG_DOUBLE_STR m = &m_data;
		LPLONG_DOUBLE_STR mv = (LPLONG_DOUBLE_STR)&v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			mov  eax, [mv]
			fld  tbyte ptr [eax]
			fdiv
			mov  eax, [m]
			fstp tbyte ptr [eax]
		}
		return *this;
	}

	// compare
	// this <  v: -
	// this == v: 0
	// this >  v: +
	int comp(const Ldouble&amp; v) const{
		LPLONG_DOUBLE_STR m = (LPLONG_DOUBLE_STR)&m_data;
		LPLONG_DOUBLE_STR mv = (LPLONG_DOUBLE_STR)&v.m_data;
		short sts;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			mov  eax, [mv]
			fld  tbyte ptr [eax]
			lea  eax, [sts]
			fcompp
			fnstsw word ptr [eax]
		}
		return ((sts &amp; 0x4100) - 1) ^ 0x3fff;
	}
	bool operator==(const Ldouble&amp; v) const{
		return (comp(v) == 0);
	}
	bool operator!=(const Ldouble&amp; v) const{
		return (comp(v) != 0);
	}
	bool operator<(const Ldouble&amp; v) const{
		return (comp(v) < 0);
	}
	bool operator<=(const Ldouble&amp; v) const{
		return (comp(v) <= 0);
	}
	bool operator>(const Ldouble&amp; v) const{
		return (comp(v) > 0);
	}
	bool operator>=(const Ldouble&amp; v) const{
		return (comp(v) >= 0);
	}

	// cast
	operator double() {
		LPLONG_DOUBLE_STR m = (LPLONG_DOUBLE_STR)&m_data;
		double t;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fstp qword ptr [t]
		}
		return t;
	}
	operator int() {
		LPLONG_DOUBLE_STR m = (LPLONG_DOUBLE_STR)&m_data;
		double t;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fstp qword ptr [t]
		}
		return (int)t;
	}

	//friend Binary operator	 +,-,*,/
	friend  const Ldouble operator+(const  Ldouble&a, const Ldouble&b){
		Ldouble p(a);
		p += b;
		return p;
	}
	friend  const Ldouble operator-(const  Ldouble&a, const Ldouble&b){
		Ldouble p(a);
		p -= b;
		return p;
	}
	friend  const Ldouble operator*(const  Ldouble&a, const Ldouble&b){
		Ldouble p(a);
		p *= b;
		return p;
	}
	friend  const Ldouble operator/(const  Ldouble&a, const Ldouble&b){
		Ldouble p(a);
		p /= b;
		return p;
	}


	LONG_DOUBLE_STR	m_data;
};

namespace LD {
	Ldouble abs(const Ldouble&amp; s){
		Ldouble v(s);
		v.m_data.d[9] &= 0x7f;
		return v;
	}

	Ldouble sin(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fsin
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble cos(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fcos
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble tan(const Ldouble&amp; s){
		Ldouble v(s);
		double t;
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fptan
			lea  ebx, [t]
			fstp qword ptr [ebx]
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble atan(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fld1
			fpatan
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble atan2(const Ldouble&amp; x, const Ldouble&amp; y){
		Ldouble v(y);
		LPLONG_DOUBLE_STR xm = (LPLONG_DOUBLE_STR)&x.m_data;
		LPLONG_DOUBLE_STR vm = &v.m_data;
		__asm {
			mov  eax, [xm]
			fld  tbyte ptr [eax]
			mov  eax, [vm]
			fld  tbyte ptr [eax]
			fpatan
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble sqrt(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fsqrt
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble pi(){
		Ldouble v;
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			mov  eax, [m]
			fldpi
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble log(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			fldln2
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fyl2x
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble log10(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		__asm {
			fldlg2
			mov  eax, [m]
			fld  tbyte ptr [eax]
			fyl2x
			fstp tbyte ptr [eax]
		}
		return v;
	}

	Ldouble exp(const Ldouble&amp; s){
		Ldouble v(s);
		LPLONG_DOUBLE_STR m = &v.m_data;
		double half = 0.5;
		bool sign = ((m->d[9] &amp; 0x80) != 0);
		m->d[9] &= 0x7f;

		__asm {
			fldl2e                 // log2e
			mov  eax, [m]
			fld  tbyte ptr [eax]   // log2e, v
			fmul                   // log2e*v
			fld  st(0)             // log2e*v, log2e*v
			lea  ebx, [half]
			fld  qword ptr [ebx]   // log2e*v, log2e*v, 0.5
			fsub                   // log2e*v, log2e*v-0.5
			frndint                // log2e*v, (int)(log2e*v-0.5)
			fxch                   // (int)(log2e*v-0.5), log2e*v
			fsub  st(0), st(1)     // (int)(log2e*v-0.5), log2e*v - (int)(log2e*v-0.5)
			f2xm1                  // (int)(log2e*v-0.5), 2^(log2e*v - (int)(log2e*v-0.5))-1
			fld1                   // (int)(log2e*v-0.5), 2^(log2e*v - (int)(log2e*v-0.5))-1, 1
			fadd                   // (int)(log2e*v-0.5), 2^(log2e*v - (int)(log2e*v-0.5))
			fscale                 // (int)(log2e*v-0.5), 2^(log2e*v - (int)(log2e*v-0.5)) * 2^(int)(log2e*v-0.5)
			fstp tbyte ptr [eax]   // (int)(log2e*v-0.5)
			fstp qword ptr [ebx]   // 
		}

		if (sign){
			__asm {
				fld1
				mov  eax, [m]
				fld  tbyte ptr [eax]
				fdiv
				fstp tbyte ptr [eax]
			}
		}
		return v;
	}

	Ldouble pow(const Ldouble&amp; x, const Ldouble&amp; y){
		Ldouble u(x),v(y);
		LPLONG_DOUBLE_STR mx = &u.m_data;
		LPLONG_DOUBLE_STR m = &v.m_data;
		double half = 0.5;
		bool xsign = ((mx->d[9] &amp; 0x80) != 0);
		bool ysign = ((m->d[9] &amp; 0x80) != 0);
		if (xsign){
			int ny = (int)v;
			Ldouble t = ny;
			if (t != y){
				throw "Invalid value.";
			}
			xsign = (ny &amp; 1) ? true : false;
		}
		mx->d[9] &= 0x7f;
		m->d[9] &= 0x7f;

		__asm {
			fld1                   // 1
			mov  eax, [mx]
			fld  tbyte ptr [eax]   // 1, x
			fyl2x                  // log2x
			mov  eax, [m]
			fld  tbyte ptr [eax]   // log2x, v
			fmul                   // log2x*v
			fld  st(0)             // log2x*v, log2x*v
			lea  ebx, [half]
			fld  qword ptr [ebx]   // log2x*v, log2x*v, 0.5
			fsub                   // log2x*v, log2x*v-0.5
			frndint                // log2x*v, (int)(log2x*v-0.5)
			fxch                   // (int)(log2x*v-0.5), log2x*v
			fsub  st(0), st(1)     // (int)(log2x*v-0.5), log2x*v - (int)(log2x*v-0.5)
			f2xm1                  // (int)(log2x*v-0.5), 2^(log2x*v - (int)(log2x*v-0.5))-1
			fld1                   // (int)(log2x*v-0.5), 2^(log2x*v - (int)(log2x*v-0.5))-1, 1
			fadd                   // (int)(log2x*v-0.5), 2^(log2x*v - (int)(log2x*v-0.5))
			fscale                 // (int)(log2x*v-0.5), 2^(log2x*v - (int)(log2x*v-0.5)) * 2^(int)(log2x*v-0.5)
			fstp tbyte ptr [eax]   // (int)(log2x*v-0.5)
			fstp qword ptr [ebx]   // 
		}

		if (ysign){
			__asm {
				fld1
				mov  eax, [m]
				fld  tbyte ptr [eax]
				fdiv
				fstp tbyte ptr [eax]
			}
		}
		if (xsign){
			m->d[9] |= 0x80;
		}
		return v;
	}
} // end of namespace

#endif
</xmp></code></pre></blockquote>
<br />
Ldoubleクラスを使う前に、Ldouble_init()を呼び出して、FPUに拡張倍精度を指示する必要があります。<br />
このコードは動作しますが、あまり速くありません。<br />
実行速度についてはコンパイラが拡張倍精度をサポートしてくれないと、どうにもなりません。<br />
実行速度をそれほど求めていないが、仮数部64bitの精度が必要であるか、<br />
最大値が10進で300桁以上になる場合（拡張倍精度ではおよそ5000桁まで可能）にのみ有効です。<br />
Win32アプリで拡張倍精度計算を行い、同時に実行速度も求めるなら、VC以外のコンパイラ(C++ Builder等)を利用した方が良いでしょう。<br />
<br />
<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>多倍長サンプルアプリ</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid96.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid96.html</id>
		<issued>2010-12-05T18:33:24+09:00</issued>
		<modified>2010-12-05T09:33:24Z</modified>
		<summary>多桁の除算や平方根計算を実装したサンプルの16進・２進・10進電卓です。整数だけですがおよそ100万桁まで計算できます。乗算は、実数FFTとKaratsuba法を組み合わせています。この内、実数FFTには、京大の大浦博士...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[<a href="http://www.hundredsoft.jp/win7blog/log/eid94.html" target="_blank">多桁の除算</a>や<a href="http://www.hundredsoft.jp/win7blog/log/eid95.html" target="_blank">平方根計算</a>を実装したサンプルの16進・２進・10進電卓です。<br />
整数だけですがおよそ100万桁まで計算できます。<br />
<br />
<a href="http://www.hundredsoft.jp/v16cal/" target="_blank"><img src="http://www.hundredsoft.jp/win7blog/img/v16cal.gif" title="v16cal" width="32" height="32" /></a><br />
<br /><br />
乗算は、実数FFTとKaratsuba法を組み合わせています。<br />
この内、実数FFTには、<a href="http://www.kurims.kyoto-u.ac.jp/~ooura/" target="_blank">京大の大浦博士</a>のDFTコード(fftsg.c)の一部をFPU化して使っています。<br />
VC++だと拡張倍精度の long double が使えないため、できるだけFPUを使って精度を高めています。<br />
精度が上がると一度に乗算できる桁数が上がり、応答性が向上します。<br />
このときの精度については 「(*1)FFT多倍長乗算器のVLSI設計」 を参考に、最大値どうしの乗算が最大の誤差を与えると仮定し、１度に行えるFFT乗算桁数を決定しています。<br />
また、２進→１０進変換にもFFT乗算が必要になります。<br />
これには神奈川工科大学 平山博士の<a href="http://www.kurims.kyoto-u.ac.jp/~kyodo/kokyuroku/contents/pdf/1138-22.pdf" target="_blank">「(*2)分割統治法による多倍長演算の高速化」</a>を参考にしました。<br />
<br /><br />
(*1) 矢崎俊志, 阿部公輝: 「FFT 多倍長乗算器のVLSI 設計」, 日本応用数理学会論文誌, Vol.15, No.3, pp.385-401 (2005-9)<br /><br />
(*2) 平山弘: 「分割統治法による多倍長演算の高速化 (数式処理における理論と応用の研究)」, 数理解析研究所講究録 (2000), 1138: 247-255<br /><br />
<br /><br />
<hr /><br />
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>ニュートン法を使った２進多桁の整数平方根</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid95.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid95.html</id>
		<issued>2010-11-23T22:59:52+09:00</issued>
		<modified>2010-11-23T13:59:52Z</modified>
		<summary>多桁の整数値(s)の平方根 √s があったとしてニュートン法（２次漸化式）を使って(s)の平方根の整数部分を求める方法について考えます。与える引数(s)に基数のべき乗を掛けることで任意の精度に拡張できます。__前...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[多桁の整数値(s)の平方根 √s があったとして<br />

ニュートン法（２次漸化式）を使って(s)の平方根の整数部分を求める方法について考えます。<br />
与える引数(s)に基数のべき乗を掛けることで任意の精度に拡張できます。
<a href="http://www.hundredsoft.jp/win7blog/log/eid94.html">__前回同様__</a>
高次漸化式にも応用できますが、ここでは２次漸化式を使っています。<br />
<br />
√s を展開すると除算が必要になるので, (1/√s)を求め、これに(s)を乗じることとします。<br />
(1/√s) の２次漸化式は、
<blockquote><pre><code><xmp>
X(i+1) = X(i) * (3 - s * X(i)^2) / 2

</xmp></code></pre></blockquote>
と表せます。<br />

これは、<br />
<blockquote><pre><code><xmp>
Bigint iSqrt(Bigint s){
  int n = s.length(); // bit数

  Bigint x = 1;
  x <<= (n / 2);  // Newton法の初期値として, 1 << (n/2) を与える。
  Bigint m(0);
  Bigint t3 = 3;
  t3 <<= n;

  while(m != x){
    m = x;
    x *= t3 - ((s * x * x) >> n);
    x >>= (n + 1);
  }
  x *= s;         // x = s / √s = √s
  x >>= n;

  // 誤差修正
  m = x + 1;
  if (s >= m * m){
     x = m;
  }
  return x;
}

</xmp></code></pre></blockquote>
<br />
と書けます。<br />
考え方としては、計算各項を　(* 2<sup>n</sup>) することで整数を一時的に固定小数点化するものです。<br />
演算量を減らす変形を重ねているのでわかりにくいかもしれませんが、非常に短いコードです。<br />
初期値については、平方根は (n/2)桁程度になるので、その逆数もまた 2<sup>n</sup>倍することを考えれば、<br />

(n/2)桁程度であることから決定していますが、初期値が甘いのでループ回数はやや多いです。<br />
ニュートン法を使った除算については、<a href="http://www.hundredsoft.jp/win7blog/log/eid94.html">__こちら__</a>をご覧ください。<br />
<br />
「Newton法初期値の改良バージョン」はこちら<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid100.html" target="_self" title="Newton法平方根（その２）">ニュートン法を使った２進多桁の整数平方根(その２)</a>
<br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>ニュートン法を使った２進多桁の整数除算</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid94.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid94.html</id>
		<issued>2010-11-13T22:28:00+09:00</issued>
		<modified>2010-11-13T13:28:00Z</modified>
		<summary>除算 x = p / q があったとしてニュートン法（２次漸化式）を使って(q)の逆数を求め、それに(p)を乗算する方法は多桁演算の定石です。この場合、多桁の浮動小数点型に変換して演算することが多いでしょう。ここで...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[除算 x = p / q があったとして<br />
ニュートン法（２次漸化式）を使って(q)の逆数を求め、それに(p)を乗算する方法は多桁演算の定石です。<br />
この場合、多桁の浮動小数点型に変換して演算することが多いでしょう。<br />
ここでは、ニュートン法を整数演算のみで実装する方法について考えます。<br />
高次漸化式にも応用できますが、ここでは２次漸化式を使っています。<br />
<br />
1/q の２次漸化式は、<br />
<blockquote><pre><code><xmp>
X(i+1) = X(i) * (2 - q * X(i))

</xmp></code></pre></blockquote>
と表せます。<br />
ここで被除数のBit数をpb, 除数のBit数をqbとして、n = pb + qb とすれば<br />
<br />
<blockquote><pre><code><xmp>
Bigint iDiv(Bigint p, Bigint q){
  int pb = p.length(); // 被除数のbit数
  int qb = q.length(); // 除数のbit数
  int n = pb + qb;

  Bigint m(0);
  Bigint x = 1;
  x <<= pb;      // Newton法の初期値として, 1 << pb を与える。
  Bigint c2 = 2;
  c2 <<= n;

  while(m != x){
    m = x;
    x *= c2 - q * x;
    x >>= n;
  }
  x *= p;        // x = p / q
  x >>= n;

  // 誤差修正
  if (p >= (x+1)*q){
      x += 1;
  }
  return x;
}

</xmp></code></pre></blockquote>
<br />
と書けます。<br />
考え方としては、計算各項を　(* 2<sup>n</sup>) することで整数を一時的に固定小数点化するものです。<br />
演算量を減らす変形を重ねているのでわかりにくいかもしれませんが、非常に短いコードです。<br />
但し、初期値が甘いのでループ回数はやや多いです。<br />
被除数と除数の桁差が少ない場合は、<a href="http://www.hundredsoft.jp/win7blog/log/eid91.html">回復法を使った２進多桁の除算</a>が有利です。<br />
<br />
<br />
「Newton法初期値の改良バージョン」はこちら<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid99.html" target="_self" title="Newton法除算（その２）">ニュートン法を使った２進多桁の整数除算(その２)</a>
<br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>モンゴメリ乗算 サンプルコード</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid93.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid93.html</id>
		<issued>2010-10-24T21:43:18+09:00</issued>
		<modified>2010-10-24T12:43:18Z</modified>
		<summary>ウィキぺディアでモンゴメリ乗算を検索すると、わかり易く詳しい説明が載っている。残念ながらこの説明全体をプログラミングしたものが見つからなかったのでC++ソースを書いてみた。// モンゴメリ乗算剰余演算 c ...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[ウィキぺディアで<a href="http://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%82%B4%E3%83%A1%E3%83%AA%E4%B9%97%E7%AE%97" target="_blank" title="モンゴメリ乗算">モンゴメリ乗算</a>を検索すると、わかり易く詳しい説明が載っている。
<br />
残念ながらこの説明全体をプログラミングしたものが見つからなかったのでC++ソースを書いてみた。<br />
<br />
<blockquote><pre><code><xmp>
// モンゴメリ乗算剰余演算 c = (a*b) mod nを求める
// gcd(n,r) == 1 となること。(nは奇数であれば良い)
//
Bigint Montgomery(const Bigint&amp; a, const Bigint&amp; b, const Bigint&amp; n) const{
  // n を法とする
  // Bit長を調べる(nb)
  int nb = n.length();

  // r: nより大きな２のべき
  Bigint r(1);
  r <<= nb;

  // r2 = r^2 mod n
  Bigint r2(r*r);
  r2 %= n;

  // n*n2 ≡ -1 mod r
  Bigint n2 = 0; /* 求めるN' */
  Bigint t = 0;
  Bigint vi = 1;
  int ni = nb;
  while (ni--){ /* Rのトップビットを除いたビット数分繰り返す */
    if ((t &amp; 1) == 0){
      /* ゼロになっているビットがあったら、N'のその部分を1にする（NはRと互いに素なので必ず奇数）*/
      t += n; /* 掛け算だが、二進数一桁の掛け算なので実質は足し算 */
      n2 += vi; /* N'のその部分を1にする */
    }
    t >>= 1; /* 必ず端数が出るが切り捨てる */
    vi <<= 1; /* Rは2の冪なので、絶対端数は出ない */
  }
  // ここまでで、今後計算に必要になる、r2,n,nb,n2が得られる。
  // つまりnを法とするモンゴメリクラスを作成するなら
  // 引数nをコンストラクタとするクラスを作成し、
  // r2,n,nb,n2をメンバ変数とする。


  // aのモンゴメリ表現をam, bのモンゴメリ表現をbmとする
  // t は作業領域
  t = a * r2;
  Bigint am = t * n2;
  am.hibitmask(nb); // mod Rの意味,(nb)bit以上を0クリア
  am *= n;
  am += t;
  am >>= nb; // 1/Rの意味
  if (am >= n) am -= n;

  t = b * r2;
  Bigint bm = t * n2;
  bm.hibitmask(nb); // mod Rの意味,(nb)bit以上を0クリア
  bm *= n;
  bm += t;
  bm >>= nb; // 1/Rの意味
  if (bm >= n) bm -= n;

  // cm: am * bm のモンゴメリリダクション
  t = (am * bm);
  Bigint cm = t * n2;
  cm.hibitmask(nb); // mod Rの意味,(nb)bit以上を0クリア
  cm *= n;
  cm += t;
  cm >>= nb; // 1/Rの意味
  if (cm >= n) cm -= n;

  // cmのモンゴメリリダクション
  t = cm;
  Bigint c = t * n2;
  c.hibitmask(nb); // mod Rの意味,(nb)bit以上を0クリア
  c *= n;
  c += t;
  c >>= nb; // 1/Rの意味
  if (c >= n) c -= n;

  return c;
}

</xmp></code></pre></blockquote>
<br />
<br />
ここでは、できるだけwikipediaの説明と合致するように書きましたが、<br />
実利用の際には、r2 = r^2 mod n の計算が重いので、<br />
（これが早ければ、そもそもモンゴメリ演算の必要がない）<br />
nを法とするモンゴメリクラスを作成するのが良いです。<br />
つまりコード中にも書いてあるように、引数nをコンストラクタとしたモンゴメリクラスを作成し、r2,n,nb,n2はメンバ変数にして、モンゴメリリダクション,
 乗算剰余演算, 加減算剰余演算, 冪剰余演算等は、モンゴメリクラスのMethodにします。<br />
<br />
※ここで書いた乗算は「乗算剰余演算」の項の上段にある方法です。
<br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/log/eid98.html target="_self">モンゴメリ冪剰余サンプルコード</a>
&nbsp;&nbsp;&nbsp;
<a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>回復法を使った２進多桁の除算(その２)</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid92.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid92.html</id>
		<issued>2010-10-10T09:57:58+09:00</issued>
		<modified>2010-10-10T00:57:58Z</modified>
		<summary>前回同様、除算 a = x / y があったとして式を変形して、a = (x * (2^(2k)-1)/y + 2^k) &gt;&gt; 2k  (k:=被除数のbit数)とすれば、逆数を求める部分((2^(2k)-1)/y)の回復法もまた特殊な被除数のため、簡単なものに変形...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[<a href="http://www.hundredsoft.jp/win7blog/log/eid91.html" target="_self" title="回復法を使った２進多桁の除算">前回同様</a>、除算 a = x / y があったとして<br />
式を変形して、<br />
<blockquote><pre><code><xmp>
a = (x * (2^(2k)-1)/y + 2^k) >> 2k  (k:=被除数のbit数)

</xmp></code></pre></blockquote>
とすれば、逆数を求める部分((2^(2k)-1)/y)の回復法もまた特殊な被除数のため、簡単なものに変形できる。<br />
<blockquote><pre><code><xmp>
Bigint iDiv(Bigint x, Bigint y){
  int xb = x.length(); // 被除数のbit数
  int yb = y.length(); // 除数のbit数
  int n = xb * 2 - 1; // ループ回数

  Bigint a(0), m(0);
  while (n--){
    m |= 1;
    a <<= 1;
    if (m >= y){
      m -= y;
      a |= 1;
    }
    m <<= 1;
  }
  a *= x;
  m = 1;
  m <<= xb;
  a += m;
  return a >> (xb*2-1);
}

</xmp></code></pre></blockquote>
この方法は、被除数bit数の倍のループとなり、これが最大の減算回数になります。<br />
しかし誤差が出ないので乗算は１回だけで済みます。<br />
前回の方法はbit差に依存したループ回数なので多桁にも応用できますが、この方法だと被除数が大きいとループ回数が多くなってしまいます。
<br />
<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid91.html">桁差が小さい時に有利な方法</a><br />
<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid99.html">ニュートン法を使った２進多桁の整数除算</a><br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
	<entry>
		<title>回復法を使った２進多桁の除算</title>
		<link rel="alternate" type="text/html" href="http://www.hundredsoft.jp/win7blog/log/eid91.html" />
		<id>http://www.hundredsoft.jp/win7blog/log/eid91.html</id>
		<issued>2010-10-03T08:14:11+09:00</issued>
		<modified>2010-10-02T23:14:11Z</modified>
		<summary>除算 a = x / y があったとして回復法を使うと被除数のbit数分の加算・減算を繰り返し行うことになる式を変形して、a = (x * ((2^k)/y) &gt;&gt; k  (k:=被除数のbit数)とすれば、逆数を求める部分((2^k)/y)の回復法は特...</summary>
		<author>
			<name>HUNDREDSOFT</name>
		</author>
		<dc:subject>プログラムメモ</dc:subject>
		<content mode="escaped" type="text/html" xml:lang="ja"><![CDATA[除算 a = x / y があったとして<br />
回復法を使うと被除数のbit数分の加算・減算を繰り返し行うことになる<br />
式を変形して、<br />
<blockquote><pre><code><xmp>
a = (x * ((2^k)/y) >> k  (k:=被除数のbit数)

</xmp></code></pre></blockquote>
とすれば、逆数を求める部分((2^k)/y)の回復法は特殊な被除数のため、簡単なものに変形できる。<br />
<blockquote><pre><code><xmp>
Bigint iDiv(Bigint x, Bigint y){
  Bigint a(0), m(1);
  int xb = x.length(); // 被除数のbit数
  int yb = y.length(); // 除数のbit数
  int n = xb - yb + 1; // ループ回数(bit差+1)

  m <<= yb-1;
  while (n--){
    a <<= 1;
    if (m >= y){
      m -= y;
      a |= 1;
    }
    m <<= 1;
  }
  a *= x;
  a >>= (xb - 1);

  // 誤差修正(ここでのaは,正解より1or2小さい場合がある)
  m = y * a;
  while(x > m){
    m += y;
    if (x > m)
      a += 1;
  }
  return a;
}

</xmp></code></pre></blockquote>
<br />
と書ける。<br />
計算量は最大でもbit差程度の加減算と２回の乗算なので<br />
bit差が数100のオーダーならNewton法を使うより有利かも。<br />
<br />
<a href="http://www.hundredsoft.jp/win7blog/log/eid99.html">ニュートン法を使った２進多桁の整数除算</a><br />
<br />
(注)ここでのBigintクラスは、多倍長整数を格納する仮想のクラスであり、実在するものではありません。<br />
<br />
<hr>
Tags: <a href="http://www.hundredsoft.jp/win7blog/sb.cgi?cid=11" target="_self">プログラムメモ</a>]]></content>
	</entry>
</feed>

