| ... | ... | @@ -63,6 +63,11 @@ pub fn calcLimbLen(scalar: anytype) usize { |
| 63 | 63 | } |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | /// Same as `calcToStringLimbsBufferLen`, without the useless base check. |
| 67 | pub fn calcLog10LimbsBufferLen(a_len: usize) usize { |
| 68 | return a_len + 2 + a_len + calcDivLimbsBufferLen(a_len, 1); |
| 69 | } |
| 70 | |
| 66 | 71 | pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize { |
| 67 | 72 | if (math.isPowerOfTwo(base)) |
| 68 | 73 | return 0; |
| ... | ... | @@ -2670,6 +2675,62 @@ pub const Const = struct { |
| 2670 | 2675 | } |
| 2671 | 2676 | return @min(result, bits); |
| 2672 | 2677 | } |
| 2678 | |
| 2679 | /// Calculate the base 2 logarithm, rounded down. |
| 2680 | pub fn log2(a: Const) Limb { |
| 2681 | return a.limbs.len * @bitSizeOf(Limb) - 1 - @clz(a.limbs[a.limbs.len - 1]); |
| 2682 | } |
| 2683 | |
| 2684 | /// Calculate the base 10 logarithm, rounded down. |
| 2685 | /// |
| 2686 | /// The allocator is used to allocate a temporary buffer. |
| 2687 | pub fn log10Alloc(a: Const, allocator: Allocator) Allocator.Error!Limb { |
| 2688 | const limbs_buffer = try allocator.alloc(Limb, calcLog10LimbsBufferLen(a.limbs.len)); |
| 2689 | defer allocator.free(limbs_buffer); |
| 2690 | |
| 2691 | return a.log10(limbs_buffer); |
| 2692 | } |
| 2693 | |
| 2694 | /// Calculate the base 10 logarithm, rounded down. |
| 2695 | /// |
| 2696 | /// `limbs_buffer` is used for temporary storage. The amount required is given by `calcLog10LimbsBufferLen`. |
| 2697 | pub fn log10(a: Const, limbs_buffer: []Limb) Limb { |
| 2698 | const max_digits_per_limb = std.math.log10(std.math.maxInt(Limb)); |
| 2699 | const limb_base = comptime calc: { |
| 2700 | var limb_base: comptime_int = 1; |
| 2701 | for (0..max_digits_per_limb) |_| limb_base *= 10; |
| 2702 | break :calc limb_base; |
| 2703 | }; |
| 2704 | const limb_base_as_bigint: Const = .{ .limbs = &.{limb_base}, .positive = true }; |
| 2705 | |
| 2706 | var q: Mutable = .{ |
| 2707 | .limbs = limbs_buffer[0 .. a.limbs.len + 2], |
| 2708 | .positive = true, |
| 2709 | .len = a.limbs.len, |
| 2710 | }; |
| 2711 | @memcpy(q.limbs[0..a.limbs.len], a.limbs); |
| 2712 | |
| 2713 | var remainder: Mutable = .{ |
| 2714 | .limbs = limbs_buffer[q.limbs.len..][0..a.limbs.len], |
| 2715 | .positive = true, |
| 2716 | .len = 1, |
| 2717 | }; |
| 2718 | |
| 2719 | const division_buf = limbs_buffer[q.limbs.len + remainder.limbs.len ..]; |
| 2720 | |
| 2721 | var num_digits: Limb = 0; |
| 2722 | while (q.len >= 2) { |
| 2723 | q.divTrunc(&remainder, q.toConst(), limb_base_as_bigint, division_buf); |
| 2724 | num_digits += max_digits_per_limb; |
| 2725 | } |
| 2726 | var remaining_limb = q.limbs[0]; |
| 2727 | while (remaining_limb != 0) { |
| 2728 | remaining_limb /= 10; |
| 2729 | num_digits += 1; |
| 2730 | } |
| 2731 | |
| 2732 | return num_digits - 1; |
| 2733 | } |
| 2673 | 2734 | }; |
| 2674 | 2735 | |
| 2675 | 2736 | /// An arbitrary-precision big integer along with an allocator which manages the memory. |