Skip to main content

atmos/os_lib/js/
bigint.rs

1//! 任意精度整数 BigInt の実装。
2//!
3//! ECMAScript の BigInt セマンティクスに沿った符号付き多倍長整数。
4//! 内部表現は「符号 + ベース 2^32 のリム列(リトルエンディアン: limbs[0] が最下位)」。
5//! ゼロは `negative=false` かつ `limbs` 空(正規形)で表す。
6//! no_std 環境のため alloc のみ使用し、除算は素朴な long division を用いる。
7
8use alloc::string::String;
9use alloc::vec::Vec;
10use core::cmp::Ordering;
11
12/// ベース 2^32 のリムで表す符号付き任意精度整数。
13#[derive(Clone, PartialEq, Eq)]
14pub struct BigInt {
15    /// true なら負。ゼロのときは必ず false(正規形)。
16    negative: bool,
17    /// 絶対値のリム列(リトルエンディアン)。末尾の 0 は持たない(正規形)。
18    limbs: Vec<u32>,
19}
20
21impl BigInt {
22    /// 値 0。
23    pub fn zero() -> Self {
24        BigInt {
25            negative: false,
26            limbs: Vec::new(),
27        }
28    }
29
30    /// ゼロかどうか。
31    pub fn is_zero(&self) -> bool {
32        self.limbs.is_empty()
33    }
34
35    /// 末尾の 0 リムを除去し、ゼロなら符号を正に揃える(正規形化)。
36    fn normalize(mut self) -> Self {
37        while let Some(&last) = self.limbs.last() {
38            if last == 0 {
39                self.limbs.pop();
40            } else {
41                break;
42            }
43        }
44        if self.limbs.is_empty() {
45            self.negative = false;
46        }
47        self
48    }
49
50    /// i64 から生成。
51    pub fn from_i64(mut v: i64) -> Self {
52        if v == 0 {
53            return BigInt::zero();
54        }
55        let negative = v < 0;
56        // i64::MIN の絶対値はオーバーフローするため u64 で扱う。
57        let mut mag = if negative {
58            (v as i128).unsigned_abs()
59        } else {
60            v as u128
61        };
62        let _ = &mut v;
63        let mut limbs = Vec::new();
64        while mag > 0 {
65            limbs.push((mag & 0xFFFF_FFFF) as u32);
66            mag >>= 32;
67        }
68        BigInt { negative, limbs }.normalize()
69    }
70
71    /// u64 から生成(常に非負)。`DataView.prototype.getBigUint64` 用。
72    pub fn from_u64(v: u64) -> Self {
73        if v == 0 {
74            return BigInt::zero();
75        }
76        let mut mag = v;
77        let mut limbs = Vec::new();
78        while mag > 0 {
79            limbs.push((mag & 0xFFFF_FFFF) as u32);
80            mag >>= 32;
81        }
82        BigInt { negative: false, limbs }.normalize()
83    }
84
85    /// f64 から生成(整数値のみ受理。小数・非有限は None)。
86    pub fn from_f64(v: f64) -> Option<Self> {
87        if !v.is_finite() {
88            return None;
89        }
90        if libm::trunc(v) != v {
91            return None;
92        }
93        if v == 0.0 {
94            return Some(BigInt::zero());
95        }
96        let negative = v < 0.0;
97        let mut mag = libm::fabs(v);
98        // 2^32 進で下位から取り出す。f64 は 2^53 まで整数を正確に表現できるが、
99        // それを超える大きさも近似的に分解する(仕様の厳密さより実用性を優先)。
100        let mut limbs = Vec::new();
101        let base = 4294967296.0_f64; // 2^32
102        while mag >= 1.0 {
103            let rem = mag - libm::floor(mag / base) * base;
104            limbs.push(rem as u32);
105            mag = libm::floor(mag / base);
106        }
107        Some(BigInt { negative, limbs }.normalize())
108    }
109
110    /// 十進文字列をパース(先頭に符号可、`_` 区切り許容)。失敗で None。
111    pub fn parse_decimal(s: &str) -> Option<Self> {
112        let t = s.trim();
113        if t.is_empty() {
114            return Some(BigInt::zero());
115        }
116        let (negative, digits) = match t.strip_prefix('-') {
117            Some(rest) => (true, rest),
118            None => (false, t.strip_prefix('+').unwrap_or(t)),
119        };
120        if digits.is_empty() {
121            return None;
122        }
123        let mut acc = BigInt::zero();
124        let ten = BigInt::from_i64(10);
125        for ch in digits.chars() {
126            if ch == '_' {
127                continue;
128            }
129            let d = ch.to_digit(10)?;
130            acc = acc.mul(&ten).add(&BigInt::from_i64(d as i64));
131        }
132        acc.negative = negative;
133        Some(acc.normalize())
134    }
135
136    /// 文字列をパース(0x/0o/0b 接頭辞対応、それ以外は十進)。
137    pub fn parse_str(s: &str) -> Option<Self> {
138        let t = s.trim();
139        let (neg, body) = match t.strip_prefix('-') {
140            Some(r) => (true, r),
141            None => (false, t.strip_prefix('+').unwrap_or(t)),
142        };
143        let parsed = if let Some(h) = body.strip_prefix("0x").or_else(|| body.strip_prefix("0X")) {
144            Self::parse_radix(h, 16)
145        } else if let Some(o) = body.strip_prefix("0o").or_else(|| body.strip_prefix("0O")) {
146            Self::parse_radix(o, 8)
147        } else if let Some(b) = body.strip_prefix("0b").or_else(|| body.strip_prefix("0B")) {
148            Self::parse_radix(b, 2)
149        } else {
150            Self::parse_decimal(body)
151        };
152        parsed.map(|mut v| {
153            if neg {
154                v.negative = !v.negative;
155            }
156            v.normalize()
157        })
158    }
159
160    /// 指定基数(2〜16)の桁列をパース。
161    fn parse_radix(digits: &str, radix: u32) -> Option<Self> {
162        if digits.is_empty() {
163            return None;
164        }
165        let mut acc = BigInt::zero();
166        let base = BigInt::from_i64(radix as i64);
167        for ch in digits.chars() {
168            if ch == '_' {
169                continue;
170            }
171            let d = ch.to_digit(radix)?;
172            acc = acc.mul(&base).add(&BigInt::from_i64(d as i64));
173        }
174        Some(acc)
175    }
176
177    /// 絶対値の大小比較。
178    fn cmp_magnitude(&self, other: &Self) -> Ordering {
179        if self.limbs.len() != other.limbs.len() {
180            return self.limbs.len().cmp(&other.limbs.len());
181        }
182        // 上位リムから比較。
183        for i in (0..self.limbs.len()).rev() {
184            if self.limbs[i] != other.limbs[i] {
185                return self.limbs[i].cmp(&other.limbs[i]);
186            }
187        }
188        Ordering::Equal
189    }
190
191    /// 符号込みの全順序比較。
192    #[allow(clippy::should_implement_trait)]
193    pub fn cmp(&self, other: &Self) -> Ordering {
194        match (self.negative, other.negative) {
195            (false, true) => Ordering::Greater,
196            (true, false) => Ordering::Less,
197            (false, false) => self.cmp_magnitude(other),
198            (true, true) => other.cmp_magnitude(self),
199        }
200    }
201
202    /// 絶対値の加算(符号は無視)。
203    fn add_magnitude(a: &[u32], b: &[u32]) -> Vec<u32> {
204        let mut out = Vec::with_capacity(a.len().max(b.len()) + 1);
205        let mut carry: u64 = 0;
206        let n = a.len().max(b.len());
207        for i in 0..n {
208            let av = *a.get(i).unwrap_or(&0) as u64;
209            let bv = *b.get(i).unwrap_or(&0) as u64;
210            let sum = av + bv + carry;
211            out.push((sum & 0xFFFF_FFFF) as u32);
212            carry = sum >> 32;
213        }
214        if carry > 0 {
215            out.push(carry as u32);
216        }
217        out
218    }
219
220    /// 絶対値の減算 a - b(a >= b を前提)。
221    fn sub_magnitude(a: &[u32], b: &[u32]) -> Vec<u32> {
222        let mut out = Vec::with_capacity(a.len());
223        let mut borrow: i64 = 0;
224        for i in 0..a.len() {
225            let av = a[i] as i64;
226            let bv = *b.get(i).unwrap_or(&0) as i64;
227            let mut diff = av - bv - borrow;
228            if diff < 0 {
229                diff += 1 << 32;
230                borrow = 1;
231            } else {
232                borrow = 0;
233            }
234            out.push((diff & 0xFFFF_FFFF) as u32);
235        }
236        out
237    }
238
239    /// 加算。
240    pub fn add(&self, other: &Self) -> Self {
241        if self.negative == other.negative {
242            // 同符号: 絶対値を足して符号は据え置き。
243            BigInt {
244                negative: self.negative,
245                limbs: Self::add_magnitude(&self.limbs, &other.limbs),
246            }
247            .normalize()
248        } else {
249            // 異符号: 絶対値の大きい方から小さい方を引く。
250            match self.cmp_magnitude(other) {
251                Ordering::Equal => BigInt::zero(),
252                Ordering::Greater => BigInt {
253                    negative: self.negative,
254                    limbs: Self::sub_magnitude(&self.limbs, &other.limbs),
255                }
256                .normalize(),
257                Ordering::Less => BigInt {
258                    negative: other.negative,
259                    limbs: Self::sub_magnitude(&other.limbs, &self.limbs),
260                }
261                .normalize(),
262            }
263        }
264    }
265
266    /// 減算。
267    pub fn sub(&self, other: &Self) -> Self {
268        // a - b = a + (-b)
269        let neg_other = BigInt {
270            negative: !other.negative,
271            limbs: other.limbs.clone(),
272        }
273        .normalize();
274        self.add(&neg_other)
275    }
276
277    /// 符号反転。
278    pub fn neg(&self) -> Self {
279        if self.is_zero() {
280            return BigInt::zero();
281        }
282        BigInt {
283            negative: !self.negative,
284            limbs: self.limbs.clone(),
285        }
286    }
287
288    /// 絶対値。
289    pub fn abs(&self) -> Self {
290        BigInt {
291            negative: false,
292            limbs: self.limbs.clone(),
293        }
294    }
295
296    /// 乗算(素朴な O(n*m) 筆算)。
297    pub fn mul(&self, other: &Self) -> Self {
298        if self.is_zero() || other.is_zero() {
299            return BigInt::zero();
300        }
301        let mut out = alloc::vec![0u32; self.limbs.len() + other.limbs.len()];
302        for (i, &a) in self.limbs.iter().enumerate() {
303            let mut carry: u64 = 0;
304            for (j, &b) in other.limbs.iter().enumerate() {
305                let idx = i + j;
306                let cur = out[idx] as u64 + (a as u64) * (b as u64) + carry;
307                out[idx] = (cur & 0xFFFF_FFFF) as u32;
308                carry = cur >> 32;
309            }
310            // 端のキャリーを伝播。
311            let mut k = i + other.limbs.len();
312            while carry > 0 {
313                let cur = out[k] as u64 + carry;
314                out[k] = (cur & 0xFFFF_FFFF) as u32;
315                carry = cur >> 32;
316                k += 1;
317            }
318        }
319        BigInt {
320            negative: self.negative != other.negative,
321            limbs: out,
322        }
323        .normalize()
324    }
325
326    /// 絶対値どうしの除算 → (商, 剰余) を絶対値で返す。
327    /// 素朴なビット単位の long division(速度より明快さを優先)。
328    fn divmod_magnitude(a: &[u32], b: &[u32]) -> (Vec<u32>, Vec<u32>) {
329        // b == 0 は呼び出し側で弾く前提。
330        let dividend = BigInt {
331            negative: false,
332            limbs: a.to_vec(),
333        }
334        .normalize();
335        let divisor = BigInt {
336            negative: false,
337            limbs: b.to_vec(),
338        }
339        .normalize();
340        if dividend.cmp_magnitude(&divisor) == Ordering::Less {
341            return (Vec::new(), dividend.limbs);
342        }
343        // ビット長を求める。
344        let total_bits = dividend.limbs.len() * 32;
345        let mut quotient = BigInt::zero();
346        let mut remainder = BigInt::zero();
347        let one = BigInt::from_i64(1);
348        for i in (0..total_bits).rev() {
349            // remainder <<= 1
350            remainder = remainder.shl_bits(1);
351            // remainder |= bit i of dividend
352            let limb = i / 32;
353            let bit = i % 32;
354            if (dividend.limbs[limb] >> bit) & 1 == 1 {
355                remainder = remainder.add(&one);
356            }
357            if remainder.cmp_magnitude(&divisor) != Ordering::Less {
358                remainder = BigInt {
359                    negative: false,
360                    limbs: Self::sub_magnitude(&remainder.limbs, &divisor.limbs),
361                }
362                .normalize();
363                quotient = quotient.set_bit(i);
364            }
365        }
366        (quotient.normalize().limbs, remainder.normalize().limbs)
367    }
368
369    /// 絶対値を左へ bit ビットシフト(内部用、符号は維持)。
370    fn shl_bits(&self, bits: usize) -> Self {
371        if self.is_zero() || bits == 0 {
372            return self.clone();
373        }
374        let limb_shift = bits / 32;
375        let bit_shift = bits % 32;
376        let mut out = alloc::vec![0u32; self.limbs.len() + limb_shift + 1];
377        for (i, &v) in self.limbs.iter().enumerate() {
378            let val = (v as u64) << bit_shift;
379            out[i + limb_shift] |= (val & 0xFFFF_FFFF) as u32;
380            out[i + limb_shift + 1] |= (val >> 32) as u32;
381        }
382        BigInt {
383            negative: self.negative,
384            limbs: out,
385        }
386        .normalize()
387    }
388
389    /// 絶対値を右へ bit ビットシフト(内部用、符号は維持。算術的切り捨て)。
390    fn shr_bits(&self, bits: usize) -> Self {
391        if self.is_zero() || bits == 0 {
392            return self.clone();
393        }
394        let limb_shift = bits / 32;
395        let bit_shift = bits % 32;
396        if limb_shift >= self.limbs.len() {
397            return BigInt::zero();
398        }
399        let mut out = alloc::vec![0u32; self.limbs.len() - limb_shift];
400        for i in 0..out.len() {
401            let lo = self.limbs[i + limb_shift] >> bit_shift;
402            let hi = if bit_shift > 0 && i + limb_shift + 1 < self.limbs.len() {
403                self.limbs[i + limb_shift + 1] << (32 - bit_shift)
404            } else {
405                0
406            };
407            out[i] = lo | hi;
408        }
409        BigInt {
410            negative: self.negative,
411            limbs: out,
412        }
413        .normalize()
414    }
415
416    /// ビット i を 1 にした新しい値を返す(絶対値操作・内部用)。
417    fn set_bit(&self, i: usize) -> Self {
418        let limb = i / 32;
419        let bit = i % 32;
420        let mut limbs = self.limbs.clone();
421        if limb >= limbs.len() {
422            limbs.resize(limb + 1, 0);
423        }
424        limbs[limb] |= 1 << bit;
425        BigInt {
426            negative: self.negative,
427            limbs,
428        }
429    }
430
431    /// 除算(商)。ゼロ除算は None。商は 0 方向への切り捨て(truncation)。
432    pub fn div(&self, other: &Self) -> Option<Self> {
433        if other.is_zero() {
434            return None;
435        }
436        let (q, _) = Self::divmod_magnitude(&self.limbs, &other.limbs);
437        Some(
438            BigInt {
439                negative: self.negative != other.negative,
440                limbs: q,
441            }
442            .normalize(),
443        )
444    }
445
446    /// 剰余。ゼロ除算は None。符号は被除数に従う(ECMAScript 準拠)。
447    pub fn rem(&self, other: &Self) -> Option<Self> {
448        if other.is_zero() {
449            return None;
450        }
451        let (_, r) = Self::divmod_magnitude(&self.limbs, &other.limbs);
452        Some(
453            BigInt {
454                negative: self.negative,
455                limbs: r,
456            }
457            .normalize(),
458        )
459    }
460
461    /// 累乗(指数は非負 BigInt のみ。負指数は None)。二乗法で計算。
462    pub fn pow(&self, exp: &Self) -> Option<Self> {
463        if exp.negative {
464            return None;
465        }
466        if exp.is_zero() {
467            return Some(BigInt::from_i64(1));
468        }
469        let mut result = BigInt::from_i64(1);
470        let mut base = self.clone();
471        let mut e = exp.clone();
472        let two = BigInt::from_i64(2);
473        while !e.is_zero() {
474            // e が奇数なら result *= base
475            let (_, r) = Self::divmod_magnitude(&e.limbs, &two.limbs);
476            let odd = !r.is_empty();
477            if odd {
478                result = result.mul(&base);
479            }
480            base = base.mul(&base);
481            e = e.shr_bits(1).abs();
482        }
483        Some(result)
484    }
485
486    /// 十進文字列化。
487    pub fn to_decimal_string(&self) -> String {
488        if self.is_zero() {
489            return String::from("0");
490        }
491        // 絶対値を 10^9 チャンクで割り続けて下位から桁を得る。
492        let mut digits_rev: Vec<u32> = Vec::new();
493        let chunk = BigInt::from_i64(1_000_000_000);
494        let mut cur = self.abs();
495        while !cur.is_zero() {
496            let (q, r) = Self::divmod_magnitude(&cur.limbs, &chunk.limbs);
497            let rem_val = limbs_to_u64(&r) as u32;
498            digits_rev.push(rem_val);
499            cur = BigInt {
500                negative: false,
501                limbs: q,
502            }
503            .normalize();
504        }
505        let mut s = String::new();
506        if self.negative {
507            s.push('-');
508        }
509        // 最上位チャンクは前ゼロなし、それ以降は 9 桁ゼロ詰め。
510        for (i, chunk_val) in digits_rev.iter().rev().enumerate() {
511            if i == 0 {
512                s.push_str(&alloc::format!("{}", chunk_val));
513            } else {
514                s.push_str(&alloc::format!("{:09}", chunk_val));
515            }
516        }
517        s
518    }
519
520    /// 近似的に f64 へ変換(Number(bigint) 用。大きすぎる値は Infinity に近づく)。
521    pub fn to_f64(&self) -> f64 {
522        let mut result = 0.0_f64;
523        let base = 4294967296.0_f64; // 2^32
524        for &limb in self.limbs.iter().rev() {
525            result = result * base + (limb as f64);
526        }
527        if self.negative {
528            -result
529        } else {
530            result
531        }
532    }
533
534    /// 1 かどうか(絶対値が 1 で正)。
535    pub fn is_one(&self) -> bool {
536        !self.negative && self.limbs.len() == 1 && self.limbs[0] == 1
537    }
538
539    /// このビット長(絶対値を表すのに必要な最小ビット数)。ゼロは 0。
540    fn bit_length(&self) -> usize {
541        match self.limbs.last() {
542            None => 0,
543            Some(&top) => (self.limbs.len() - 1) * 32 + (32 - top.leading_zeros() as usize),
544        }
545    }
546
547    /// 指定リム数の「2 の補数表現」をリトルエンディアンの u32 列で返す。
548    /// 負数は ~|x| + 1 を width リム幅で計算する。正数はゼロ拡張。
549    fn to_twos_complement(&self, width: usize) -> Vec<u32> {
550        let mut out = alloc::vec![0u32; width];
551        for (i, slot) in out.iter_mut().enumerate() {
552            *slot = *self.limbs.get(i).unwrap_or(&0);
553        }
554        if self.negative {
555            // ビット反転して +1。
556            for slot in out.iter_mut() {
557                *slot = !*slot;
558            }
559            let mut carry = 1u64;
560            for slot in out.iter_mut() {
561                let v = *slot as u64 + carry;
562                *slot = (v & 0xFFFF_FFFF) as u32;
563                carry = v >> 32;
564                if carry == 0 {
565                    break;
566                }
567            }
568        }
569        out
570    }
571
572    /// width リム幅の 2 の補数表現(リトルエンディアン)から BigInt を復元する。
573    /// 最上位ビットが 1 なら負数とみなす。
574    fn from_twos_complement(mut limbs: Vec<u32>) -> Self {
575        let negative = limbs
576            .last()
577            .map(|&top| (top >> 31) & 1 == 1)
578            .unwrap_or(false);
579        if negative {
580            // 2 の補数を反転して大きさを得る: |x| = ~bits + 1。
581            for slot in limbs.iter_mut() {
582                *slot = !*slot;
583            }
584            let mut carry = 1u64;
585            for slot in limbs.iter_mut() {
586                let v = *slot as u64 + carry;
587                *slot = (v & 0xFFFF_FFFF) as u32;
588                carry = v >> 32;
589                if carry == 0 {
590                    break;
591                }
592            }
593        }
594        BigInt { negative, limbs }.normalize()
595    }
596
597    /// 2 つの値のビット演算に必要なリム幅(両者の絶対値ビット長 + 符号ビット余裕)。
598    fn bitop_width(&self, other: &Self) -> usize {
599        let bits = self.bit_length().max(other.bit_length());
600        // 符号ビットのために 1 ビット余分に確保し、リム単位へ切り上げる。
601        (bits / 32) + 2
602    }
603
604    /// ビット AND(2 の補数の無限長セマンティクス)。
605    pub fn bitand(&self, other: &Self) -> Self {
606        let w = self.bitop_width(other);
607        let a = self.to_twos_complement(w);
608        let b = other.to_twos_complement(w);
609        let out: Vec<u32> = a.iter().zip(b.iter()).map(|(x, y)| x & y).collect();
610        Self::from_twos_complement(out)
611    }
612
613    /// ビット OR。
614    pub fn bitor(&self, other: &Self) -> Self {
615        let w = self.bitop_width(other);
616        let a = self.to_twos_complement(w);
617        let b = other.to_twos_complement(w);
618        let out: Vec<u32> = a.iter().zip(b.iter()).map(|(x, y)| x | y).collect();
619        Self::from_twos_complement(out)
620    }
621
622    /// ビット XOR。
623    pub fn bitxor(&self, other: &Self) -> Self {
624        let w = self.bitop_width(other);
625        let a = self.to_twos_complement(w);
626        let b = other.to_twos_complement(w);
627        let out: Vec<u32> = a.iter().zip(b.iter()).map(|(x, y)| x ^ y).collect();
628        Self::from_twos_complement(out)
629    }
630
631    /// ビット NOT(~x = -(x+1)、2 の補数の恒等式)。
632    pub fn bitnot(&self) -> Self {
633        // ~x = -x - 1
634        self.neg().sub(&BigInt::from_i64(1))
635    }
636
637    /// 左シフト(count は非負 i64。符号は保存、絶対値を count ビット左へ)。
638    pub fn shl(&self, count: i64) -> Self {
639        if count < 0 {
640            return self.shr(-count);
641        }
642        let shifted = self.shl_bits(count as usize);
643        BigInt {
644            negative: self.negative,
645            limbs: shifted.limbs,
646        }
647        .normalize()
648    }
649
650    /// 右シフト(算術シフト = 床方向。負数では -infinity 方向へ丸める ECMAScript 準拠)。
651    pub fn shr(&self, count: i64) -> Self {
652        if count < 0 {
653            return self.shl(-count);
654        }
655        let n = count as usize;
656        if !self.negative {
657            // 正数は単純な論理右シフト。
658            let shifted = self.shr_bits(n);
659            return BigInt {
660                negative: false,
661                limbs: shifted.limbs,
662            }
663            .normalize();
664        }
665        // 負数の算術右シフトは床関数: floor(x / 2^n)。
666        // |x| を n ビット右シフトし、切り捨てた下位ビットが非ゼロなら -1 する。
667        let full_limbs = n / 32;
668        let rem_bits = n % 32;
669        let mut truncated_bits = false;
670        for &l in self.limbs.iter().take(full_limbs) {
671            if l != 0 {
672                truncated_bits = true;
673                break;
674            }
675        }
676        if !truncated_bits && rem_bits > 0 {
677            if let Some(&l) = self.limbs.get(full_limbs) {
678                let mask = (1u32 << rem_bits) - 1;
679                if (l & mask) != 0 {
680                    truncated_bits = true;
681                }
682            }
683        }
684        let mag = self.shr_bits(n);
685        let mut result = BigInt {
686            negative: true,
687            limbs: mag.limbs,
688        }
689        .normalize();
690        if truncated_bits {
691            // 床方向へさらに 1 引く(負方向に大きくする)。
692            result = result.sub(&BigInt::from_i64(1));
693        }
694        result
695    }
696
697    /// BigInt.asUintN(bits, x): 下位 bits ビットを符号なし整数として解釈。
698    pub fn as_uint_n(&self, bits: u64) -> Self {
699        if bits == 0 {
700            return BigInt::zero();
701        }
702        let full_limbs = (bits / 32) as usize;
703        let rem_bits = (bits % 32) as usize;
704        let width = full_limbs + if rem_bits > 0 { 1 } else { 0 } + 1;
705        let tc = self.to_twos_complement(width);
706        let out_limbs_count = full_limbs + if rem_bits > 0 { 1 } else { 0 };
707        let mut out = alloc::vec![0u32; out_limbs_count];
708        for i in 0..full_limbs {
709            if i < tc.len() {
710                out[i] = tc[i];
711            }
712        }
713        if rem_bits > 0 && full_limbs < tc.len() {
714            let mask = (1u32 << rem_bits) - 1;
715            out[full_limbs] = tc[full_limbs] & mask;
716        }
717        // 符号なしなので最上位に符号ビットが立たないよう、そのまま大きさとして扱う。
718        BigInt {
719            negative: false,
720            limbs: out,
721        }
722        .normalize()
723    }
724
725    /// BigInt.asIntN(bits, x): 下位 bits ビットを符号付き 2 の補数として解釈。
726    pub fn as_int_n(&self, bits: u64) -> Self {
727        if bits == 0 {
728            return BigInt::zero();
729        }
730        let unsigned = self.as_uint_n(bits);
731        // 最上位ビット(bits-1)が立っていれば 2^bits を引いて負数化。
732        let top = (bits - 1) as usize;
733        let limb = top / 32;
734        let bit = top % 32;
735        let is_neg = limb < unsigned.limbs.len() && (unsigned.limbs[limb] >> bit) & 1 == 1;
736        if is_neg {
737            // result = unsigned - 2^bits
738            let two_pow = BigInt::from_i64(1).shl(bits as i64);
739            unsigned.sub(&two_pow)
740        } else {
741            unsigned
742        }
743    }
744
745    /// 下位64ビットを2の補数のビットパターンとして u64 へ切り詰める。
746    /// `DataView.prototype.setBigInt64/setBigUint64` がバイト列へ書き戻す際に使う。
747    pub fn to_u64_truncated(&self) -> u64 {
748        let unsigned = self.as_uint_n(64);
749        let low = *unsigned.limbs.first().unwrap_or(&0) as u64;
750        let high = *unsigned.limbs.get(1).unwrap_or(&0) as u64;
751        low | (high << 32)
752    }
753}
754
755/// リム列(最大 2 リム想定)を u64 に詰める補助。
756fn limbs_to_u64(limbs: &[u32]) -> u64 {
757    let mut v = 0u64;
758    for (i, &l) in limbs.iter().enumerate().take(2) {
759        v |= (l as u64) << (32 * i);
760    }
761    v
762}
763
764/// BigInt 自己テスト。(pass, total) を返す。
765/// 算術・比較・ビット演算・シフト・asIntN/asUintN・パース・文字列化を検証する。
766pub fn selftest() -> (usize, usize) {
767    let mut pass = 0usize;
768    let mut total = 0usize;
769
770    // 文字列等価で検証する小ヘルパ。
771    fn check_str(pass: &mut usize, total: &mut usize, got: &str, want: &str) {
772        *total += 1;
773        if got == want {
774            *pass += 1;
775        }
776    }
777    // 真偽値検証ヘルパ。
778    fn check_bool(pass: &mut usize, total: &mut usize, cond: bool) {
779        *total += 1;
780        if cond {
781            *pass += 1;
782        }
783    }
784    // Option<String> 検証ヘルパ(unwrap を使わずに失敗を None として扱う)。
785    // パース失敗や div/pow の None はそのまま不一致(テスト失敗)になる。
786    fn check_opt(pass: &mut usize, total: &mut usize, got: Option<String>, want: &str) {
787        *total += 1;
788        if got.as_deref() == Some(want) {
789            *pass += 1;
790        }
791    }
792
793    let bi = BigInt::from_i64;
794    let p = &mut pass;
795    let t = &mut total;
796
797    // --- パース & 文字列化 ---
798    check_opt(
799        p,
800        t,
801        BigInt::parse_str("0").map(|b| b.to_decimal_string()),
802        "0",
803    );
804    check_opt(
805        p,
806        t,
807        BigInt::parse_str("12345678901234567890").map(|b| b.to_decimal_string()),
808        "12345678901234567890",
809    );
810    check_opt(
811        p,
812        t,
813        BigInt::parse_str("-98765432109876543210").map(|b| b.to_decimal_string()),
814        "-98765432109876543210",
815    );
816    check_opt(
817        p,
818        t,
819        BigInt::parse_str("0xff").map(|b| b.to_decimal_string()),
820        "255",
821    );
822    check_opt(
823        p,
824        t,
825        BigInt::parse_str("0b1010").map(|b| b.to_decimal_string()),
826        "10",
827    );
828    check_opt(
829        p,
830        t,
831        BigInt::parse_str("0o17").map(|b| b.to_decimal_string()),
832        "15",
833    );
834    check_opt(
835        p,
836        t,
837        BigInt::parse_str("1_000_000").map(|b| b.to_decimal_string()),
838        "1000000",
839    );
840
841    // --- 加減算(桁上がり・桁借り・符号交差)---
842    check_str(p, t, &bi(2).add(&bi(3)).to_decimal_string(), "5");
843    check_opt(
844        p,
845        t,
846        BigInt::parse_str("4294967295").map(|b| b.add(&bi(1)).to_decimal_string()),
847        "4294967296",
848    );
849    check_str(p, t, &bi(5).sub(&bi(8)).to_decimal_string(), "-3");
850    check_str(p, t, &bi(-5).add(&bi(5)).to_decimal_string(), "0");
851    check_opt(
852        p,
853        t,
854        BigInt::parse_str("18446744073709551616").map(|b| b.sub(&bi(1)).to_decimal_string()),
855        "18446744073709551615",
856    );
857
858    // --- 乗算 ---
859    check_str(
860        p,
861        t,
862        &bi(123456789).mul(&bi(987654321)).to_decimal_string(),
863        "121932631112635269",
864    );
865    check_str(p, t, &bi(-7).mul(&bi(6)).to_decimal_string(), "-42");
866    check_opt(
867        p,
868        t,
869        BigInt::parse_str("99999999999999999999").and_then(|a| {
870            BigInt::parse_str("99999999999999999999").map(|b| a.mul(&b).to_decimal_string())
871        }),
872        "9999999999999999999800000000000000000001",
873    );
874
875    // --- 除算・剰余(符号は被除数に従う)---
876    check_opt(
877        p,
878        t,
879        bi(100).div(&bi(7)).map(|b| b.to_decimal_string()),
880        "14",
881    );
882    check_opt(
883        p,
884        t,
885        bi(100).rem(&bi(7)).map(|b| b.to_decimal_string()),
886        "2",
887    );
888    check_opt(
889        p,
890        t,
891        bi(-100).div(&bi(7)).map(|b| b.to_decimal_string()),
892        "-14",
893    );
894    check_opt(
895        p,
896        t,
897        bi(-100).rem(&bi(7)).map(|b| b.to_decimal_string()),
898        "-2",
899    );
900    check_bool(p, t, bi(1).div(&bi(0)).is_none());
901
902    // --- 累乗 ---
903    check_opt(
904        p,
905        t,
906        bi(2).pow(&bi(64)).map(|b| b.to_decimal_string()),
907        "18446744073709551616",
908    );
909    check_opt(p, t, bi(3).pow(&bi(0)).map(|b| b.to_decimal_string()), "1");
910    check_opt(
911        p,
912        t,
913        bi(-2).pow(&bi(3)).map(|b| b.to_decimal_string()),
914        "-8",
915    );
916
917    // --- 比較 ---
918    check_bool(p, t, bi(5).cmp(&bi(7)) == Ordering::Less);
919    check_bool(p, t, bi(-3).cmp(&bi(-9)) == Ordering::Greater);
920    check_bool(p, t, bi(42).cmp(&bi(42)) == Ordering::Equal);
921
922    // --- ビット演算(正数)---
923    check_str(
924        p,
925        t,
926        &bi(0b1100).bitand(&bi(0b1010)).to_decimal_string(),
927        "8",
928    ); // 0b1000
929    check_str(
930        p,
931        t,
932        &bi(0b1100).bitor(&bi(0b1010)).to_decimal_string(),
933        "14",
934    ); // 0b1110
935    check_str(
936        p,
937        t,
938        &bi(0b1100).bitxor(&bi(0b1010)).to_decimal_string(),
939        "6",
940    ); // 0b0110
941
942    // --- ビット演算(負数: 2 の補数の無限長セマンティクス)---
943    check_str(p, t, &bi(5).bitnot().to_decimal_string(), "-6"); // ~5n == -6n
944    check_str(p, t, &bi(-1).bitnot().to_decimal_string(), "0"); // ~(-1n) == 0n
945    check_str(p, t, &bi(-1).bitand(&bi(5)).to_decimal_string(), "5"); // -1n & 5n == 5n
946    check_str(p, t, &bi(-1).bitor(&bi(5)).to_decimal_string(), "-1"); // -1n | 5n == -1n
947    check_str(p, t, &bi(-2).bitand(&bi(3)).to_decimal_string(), "2"); // -2n & 3n == 2n
948    check_str(p, t, &bi(-1).bitxor(&bi(-1)).to_decimal_string(), "0"); // -1n ^ -1n == 0n
949
950    // --- シフト ---
951    check_str(
952        p,
953        t,
954        &bi(1).shl(64).to_decimal_string(),
955        "18446744073709551616",
956    );
957    check_str(p, t, &bi(255).shr(4).to_decimal_string(), "15");
958    // 負数の算術右シフト(床方向): -8 >> 1 == -4, -7 >> 1 == -4
959    check_str(p, t, &bi(-8).shr(1).to_decimal_string(), "-4");
960    check_str(p, t, &bi(-7).shr(1).to_decimal_string(), "-4");
961    check_str(p, t, &bi(-1).shr(5).to_decimal_string(), "-1");
962    check_str(
963        p,
964        t,
965        &bi(12345).shl(40).shr(40).to_decimal_string(),
966        "12345",
967    );
968
969    // --- asUintN / asIntN ---
970    check_str(p, t, &bi(256).as_uint_n(8).to_decimal_string(), "0");
971    check_str(p, t, &bi(257).as_uint_n(8).to_decimal_string(), "1");
972    check_str(p, t, &bi(-1).as_uint_n(8).to_decimal_string(), "255");
973    check_str(p, t, &bi(255).as_int_n(8).to_decimal_string(), "-1");
974    check_str(p, t, &bi(128).as_int_n(8).to_decimal_string(), "-128");
975    check_str(p, t, &bi(127).as_int_n(8).to_decimal_string(), "127");
976    check_str(p, t, &bi(0x8000).as_int_n(16).to_decimal_string(), "-32768");
977
978    // --- f64 変換 ---
979    check_bool(p, t, bi(9007199254740992).to_f64() == 9007199254740992.0);
980    check_bool(
981        p,
982        t,
983        BigInt::from_f64(42.0).map(|b| b.to_decimal_string()) == Some(String::from("42")),
984    );
985    check_bool(p, t, BigInt::from_f64(1.5).is_none());
986
987    (pass, total)
988}