| ... | ... | @@ -3013,7 +3013,9 @@ pub const Managed = struct { |
| 3013 | 3013 | /// |
| 3014 | 3014 | /// Returns an error if memory could not be allocated. |
| 3015 | 3015 | pub fn addScalar(r: *Managed, a: *const Managed, scalar: anytype) Allocator.Error!void { |
| 3016 | | try r.ensureAddScalarCapacity(a.toConst(), scalar); |
| 3016 | const needed = @max(a.len(), calcLimbLen(scalar)) + 1; |
| 3017 | const aliased = limbsAliasDistinct(r, a); |
| 3018 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3017 | 3019 | var m = r.toMutable(); |
| 3018 | 3020 | m.addScalar(a.toConst(), scalar); |
| 3019 | 3021 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3025,7 +3027,9 @@ pub const Managed = struct { |
| 3025 | 3027 | /// |
| 3026 | 3028 | /// Returns an error if memory could not be allocated. |
| 3027 | 3029 | pub fn add(r: *Managed, a: *const Managed, b: *const Managed) Allocator.Error!void { |
| 3028 | | try r.ensureAddCapacity(a.toConst(), b.toConst()); |
| 3030 | const needed = @max(a.len(), b.len()) + 1; |
| 3031 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3032 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3029 | 3033 | var m = r.toMutable(); |
| 3030 | 3034 | m.add(a.toConst(), b.toConst()); |
| 3031 | 3035 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3043,7 +3047,9 @@ pub const Managed = struct { |
| 3043 | 3047 | signedness: Signedness, |
| 3044 | 3048 | bit_count: usize, |
| 3045 | 3049 | ) Allocator.Error!bool { |
| 3046 | | try r.ensureTwosCompCapacity(bit_count); |
| 3050 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3051 | const needed = calcTwosCompLimbCount(bit_count); |
| 3052 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3047 | 3053 | var m = r.toMutable(); |
| 3048 | 3054 | const wrapped = m.addWrap(a.toConst(), b.toConst(), signedness, bit_count); |
| 3049 | 3055 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3056,7 +3062,9 @@ pub const Managed = struct { |
| 3056 | 3062 | /// |
| 3057 | 3063 | /// Returns an error if memory could not be allocated. |
| 3058 | 3064 | pub fn addSat(r: *Managed, a: *const Managed, b: *const Managed, signedness: Signedness, bit_count: usize) Allocator.Error!void { |
| 3059 | | try r.ensureTwosCompCapacity(bit_count); |
| 3065 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3066 | const needed = calcTwosCompLimbCount(bit_count); |
| 3067 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3060 | 3068 | var m = r.toMutable(); |
| 3061 | 3069 | m.addSat(a.toConst(), b.toConst(), signedness, bit_count); |
| 3062 | 3070 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3068,7 +3076,9 @@ pub const Managed = struct { |
| 3068 | 3076 | /// |
| 3069 | 3077 | /// Returns an error if memory could not be allocated. |
| 3070 | 3078 | pub fn sub(r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3071 | | try r.ensureCapacity(@max(a.len(), b.len()) + 1); |
| 3079 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3080 | const needed = @max(a.len(), b.len()) + 1; |
| 3081 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3072 | 3082 | var m = r.toMutable(); |
| 3073 | 3083 | m.sub(a.toConst(), b.toConst()); |
| 3074 | 3084 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3086,7 +3096,9 @@ pub const Managed = struct { |
| 3086 | 3096 | signedness: Signedness, |
| 3087 | 3097 | bit_count: usize, |
| 3088 | 3098 | ) Allocator.Error!bool { |
| 3089 | | try r.ensureTwosCompCapacity(bit_count); |
| 3099 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3100 | const needed = calcTwosCompLimbCount(bit_count); |
| 3101 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3090 | 3102 | var m = r.toMutable(); |
| 3091 | 3103 | const wrapped = m.subWrap(a.toConst(), b.toConst(), signedness, bit_count); |
| 3092 | 3104 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3105,7 +3117,9 @@ pub const Managed = struct { |
| 3105 | 3117 | signedness: Signedness, |
| 3106 | 3118 | bit_count: usize, |
| 3107 | 3119 | ) Allocator.Error!void { |
| 3108 | | try r.ensureTwosCompCapacity(bit_count); |
| 3120 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3121 | const needed = calcTwosCompLimbCount(bit_count); |
| 3122 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3109 | 3123 | var m = r.toMutable(); |
| 3110 | 3124 | m.subSat(a.toConst(), b.toConst(), signedness, bit_count); |
| 3111 | 3125 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3124,7 +3138,9 @@ pub const Managed = struct { |
| 3124 | 3138 | alias_count += 1; |
| 3125 | 3139 | if (rma.limbs.ptr == b.limbs.ptr) |
| 3126 | 3140 | alias_count += 1; |
| 3127 | | try rma.ensureMulCapacity(a.toConst(), b.toConst()); |
| 3141 | const needed = a.len() + b.len() + 1; |
| 3142 | const capacity_alias = limbsAliasDistinct(rma, a) or limbsAliasDistinct(rma, b); |
| 3143 | try rma.ensureAliasAwareCapacity(needed, capacity_alias); |
| 3128 | 3144 | var m = rma.toMutable(); |
| 3129 | 3145 | if (alias_count == 0) { |
| 3130 | 3146 | m.mulNoAlias(a.toConst(), b.toConst(), rma.allocator); |
| ... | ... | @@ -3156,8 +3172,9 @@ pub const Managed = struct { |
| 3156 | 3172 | alias_count += 1; |
| 3157 | 3173 | if (rma.limbs.ptr == b.limbs.ptr) |
| 3158 | 3174 | alias_count += 1; |
| 3159 | | |
| 3160 | | try rma.ensureTwosCompCapacity(bit_count); |
| 3175 | const needed = calcTwosCompLimbCount(bit_count); |
| 3176 | const capacity_alias = limbsAliasDistinct(rma, a) or limbsAliasDistinct(rma, b); |
| 3177 | try rma.ensureAliasAwareCapacity(needed, capacity_alias); |
| 3161 | 3178 | var m = rma.toMutable(); |
| 3162 | 3179 | if (alias_count == 0) { |
| 3163 | 3180 | m.mulWrapNoAlias(a.toConst(), b.toConst(), signedness, bit_count, rma.allocator); |
| ... | ... | @@ -3174,16 +3191,40 @@ pub const Managed = struct { |
| 3174 | 3191 | try r.ensureCapacity(calcTwosCompLimbCount(bit_count)); |
| 3175 | 3192 | } |
| 3176 | 3193 | |
| 3177 | | pub fn ensureAddScalarCapacity(r: *Managed, a: Const, scalar: anytype) !void { |
| 3178 | | try r.ensureCapacity(@max(a.limbs.len, calcLimbLen(scalar)) + 1); |
| 3194 | /// True if two distinct `Managed` parameters share the same limbs buffer. |
| 3195 | /// |
| 3196 | /// We specifically exclude the case where `@intFromPtr(a) == @intFromPtr(b)` (same object). |
| 3197 | /// When both pointers refer to the same `Managed` instance, `ensureCapacity` can reallocate |
| 3198 | /// the buffer (if needed) without creating dangling pointers for that object. |
| 3199 | fn limbsAliasDistinct(a: *const Managed, b: *const Managed) bool { |
| 3200 | return @intFromPtr(a) != @intFromPtr(b) and a.limbs.ptr == b.limbs.ptr; |
| 3201 | } |
| 3202 | |
| 3203 | /// When `aliased` is false (including when both pointers refer to the same object), |
| 3204 | /// `ensureCapacity` may reallocate; callers who rely on distinct `Managed` instances |
| 3205 | /// aliasing must ensure capacity before aliasing. |
| 3206 | /// See https://github.com/ziglang/zig/issues/6167 |
| 3207 | fn ensureAliasAwareCapacity(r: *Managed, needed: usize, aliased: bool) !void { |
| 3208 | if (aliased) { |
| 3209 | assert(needed <= r.limbs.len); |
| 3210 | } else { |
| 3211 | try r.ensureCapacity(needed); |
| 3212 | } |
| 3179 | 3213 | } |
| 3180 | 3214 | |
| 3181 | | pub fn ensureAddCapacity(r: *Managed, a: Const, b: Const) !void { |
| 3182 | | try r.ensureCapacity(@max(a.limbs.len, b.limbs.len) + 1); |
| 3215 | /// Use this function before doing `addScalar` if some of your parameters alias each other |
| 3216 | pub fn ensureAddScalarCapacity(r: *Managed, a: *const Managed, scalar: anytype) !void { |
| 3217 | try r.ensureCapacity(@max(a.len(), calcLimbLen(scalar)) + 1); |
| 3183 | 3218 | } |
| 3184 | 3219 | |
| 3185 | | pub fn ensureMulCapacity(rma: *Managed, a: Const, b: Const) !void { |
| 3186 | | try rma.ensureCapacity(a.limbs.len + b.limbs.len + 1); |
| 3220 | /// Use this function before doing `add` if some of your parameters alias each other |
| 3221 | pub fn ensureAddCapacity(r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3222 | try r.ensureCapacity(@max(a.len(), b.len()) + 1); |
| 3223 | } |
| 3224 | |
| 3225 | /// Use this function before doing `mul` if some of your parameters alias each other |
| 3226 | pub fn ensureMulCapacity(rma: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3227 | try rma.ensureCapacity(a.len() + b.len() + 1); |
| 3187 | 3228 | } |
| 3188 | 3229 | |
| 3189 | 3230 | /// q = a / b (rem r) |
| ... | ... | @@ -3192,8 +3233,10 @@ pub const Managed = struct { |
| 3192 | 3233 | /// |
| 3193 | 3234 | /// Returns an error if memory could not be allocated. |
| 3194 | 3235 | pub fn divFloor(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3195 | | try q.ensureCapacity(a.len()); |
| 3196 | | try r.ensureCapacity(b.len()); |
| 3236 | const q_alias = limbsAliasDistinct(q, a) or limbsAliasDistinct(q, b); |
| 3237 | const r_alias = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3238 | try q.ensureAliasAwareCapacity(a.len(), q_alias); |
| 3239 | try r.ensureAliasAwareCapacity(b.len(), r_alias); |
| 3197 | 3240 | var mq = q.toMutable(); |
| 3198 | 3241 | var mr = r.toMutable(); |
| 3199 | 3242 | const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len())); |
| ... | ... | @@ -3209,8 +3252,10 @@ pub const Managed = struct { |
| 3209 | 3252 | /// |
| 3210 | 3253 | /// Returns an error if memory could not be allocated. |
| 3211 | 3254 | pub fn divTrunc(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3212 | | try q.ensureCapacity(a.len()); |
| 3213 | | try r.ensureCapacity(b.len()); |
| 3255 | const q_alias = limbsAliasDistinct(q, a) or limbsAliasDistinct(q, b); |
| 3256 | const r_alias = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3257 | try q.ensureAliasAwareCapacity(a.len(), q_alias); |
| 3258 | try r.ensureAliasAwareCapacity(b.len(), r_alias); |
| 3214 | 3259 | var mq = q.toMutable(); |
| 3215 | 3260 | var mr = r.toMutable(); |
| 3216 | 3261 | const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len())); |
| ... | ... | @@ -3223,7 +3268,9 @@ pub const Managed = struct { |
| 3223 | 3268 | /// r = a << shift, in other words, r = a * 2^shift |
| 3224 | 3269 | /// r and a may alias. |
| 3225 | 3270 | pub fn shiftLeft(r: *Managed, a: *const Managed, shift: usize) !void { |
| 3226 | | try r.ensureCapacity(a.len() + (shift / limb_bits) + 1); |
| 3271 | const aliased = limbsAliasDistinct(r, a); |
| 3272 | const needed = a.len() + (shift / limb_bits) + 1; |
| 3273 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3227 | 3274 | var m = r.toMutable(); |
| 3228 | 3275 | m.shiftLeft(a.toConst(), shift); |
| 3229 | 3276 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3232,7 +3279,9 @@ pub const Managed = struct { |
| 3232 | 3279 | /// r = a <<| shift with 2s-complement saturating semantics. |
| 3233 | 3280 | /// r and a may alias. |
| 3234 | 3281 | pub fn shiftLeftSat(r: *Managed, a: *const Managed, shift: usize, signedness: Signedness, bit_count: usize) !void { |
| 3235 | | try r.ensureTwosCompCapacity(bit_count); |
| 3282 | const aliased = limbsAliasDistinct(r, a); |
| 3283 | const needed = calcTwosCompLimbCount(bit_count); |
| 3284 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3236 | 3285 | var m = r.toMutable(); |
| 3237 | 3286 | m.shiftLeftSat(a.toConst(), shift, signedness, bit_count); |
| 3238 | 3287 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3254,7 +3303,9 @@ pub const Managed = struct { |
| 3254 | 3303 | return; |
| 3255 | 3304 | } |
| 3256 | 3305 | |
| 3257 | | try r.ensureCapacity(a.len() - (shift / limb_bits)); |
| 3306 | const aliased = limbsAliasDistinct(r, a); |
| 3307 | const needed = a.len() - (shift / limb_bits); |
| 3308 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3258 | 3309 | var m = r.toMutable(); |
| 3259 | 3310 | m.shiftRight(a.toConst(), shift); |
| 3260 | 3311 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3263,7 +3314,9 @@ pub const Managed = struct { |
| 3263 | 3314 | /// r = ~a under 2s-complement wrapping semantics. |
| 3264 | 3315 | /// r and a may alias. |
| 3265 | 3316 | pub fn bitNotWrap(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void { |
| 3266 | | try r.ensureTwosCompCapacity(bit_count); |
| 3317 | const aliased = limbsAliasDistinct(r, a); |
| 3318 | const needed = calcTwosCompLimbCount(bit_count); |
| 3319 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3267 | 3320 | var m = r.toMutable(); |
| 3268 | 3321 | m.bitNotWrap(a.toConst(), signedness, bit_count); |
| 3269 | 3322 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3273,7 +3326,9 @@ pub const Managed = struct { |
| 3273 | 3326 | /// |
| 3274 | 3327 | /// a and b are zero-extended to the longer of a or b. |
| 3275 | 3328 | pub fn bitOr(r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3276 | | try r.ensureCapacity(@max(a.len(), b.len())); |
| 3329 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3330 | const needed = @max(a.len(), b.len()); |
| 3331 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3277 | 3332 | var m = r.toMutable(); |
| 3278 | 3333 | m.bitOr(a.toConst(), b.toConst()); |
| 3279 | 3334 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3285,7 +3340,8 @@ pub const Managed = struct { |
| 3285 | 3340 | if (b.isPositive()) b.len() else if (a.isPositive()) a.len() else a.len() + 1 |
| 3286 | 3341 | else if (a.isPositive()) a.len() else if (b.isPositive()) b.len() else b.len() + 1; |
| 3287 | 3342 | |
| 3288 | | try r.ensureCapacity(cap); |
| 3343 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3344 | try r.ensureAliasAwareCapacity(cap, aliased); |
| 3289 | 3345 | var m = r.toMutable(); |
| 3290 | 3346 | m.bitAnd(a.toConst(), b.toConst()); |
| 3291 | 3347 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3294,7 +3350,8 @@ pub const Managed = struct { |
| 3294 | 3350 | /// r = a ^ b |
| 3295 | 3351 | pub fn bitXor(r: *Managed, a: *const Managed, b: *const Managed) !void { |
| 3296 | 3352 | const cap = @max(a.len(), b.len()) + @intFromBool(a.isPositive() != b.isPositive()); |
| 3297 | | try r.ensureCapacity(cap); |
| 3353 | const aliased = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); |
| 3354 | try r.ensureAliasAwareCapacity(cap, aliased); |
| 3298 | 3355 | |
| 3299 | 3356 | var m = r.toMutable(); |
| 3300 | 3357 | m.bitXor(a.toConst(), b.toConst()); |
| ... | ... | @@ -3306,7 +3363,9 @@ pub const Managed = struct { |
| 3306 | 3363 | /// |
| 3307 | 3364 | /// rma's allocator is used for temporary storage to boost multiplication performance. |
| 3308 | 3365 | pub fn gcd(rma: *Managed, x: *const Managed, y: *const Managed) !void { |
| 3309 | | try rma.ensureCapacity(@min(x.len(), y.len())); |
| 3366 | const aliased = limbsAliasDistinct(rma, x) or limbsAliasDistinct(rma, y); |
| 3367 | const needed = @min(x.len(), y.len()); |
| 3368 | try rma.ensureAliasAwareCapacity(needed, aliased); |
| 3310 | 3369 | var m = rma.toMutable(); |
| 3311 | 3370 | var limbs_buffer = std.array_list.Managed(Limb).init(rma.allocator); |
| 3312 | 3371 | defer limbs_buffer.deinit(); |
| ... | ... | @@ -3317,18 +3376,20 @@ pub const Managed = struct { |
| 3317 | 3376 | /// r = a * a |
| 3318 | 3377 | pub fn sqr(rma: *Managed, a: *const Managed) !void { |
| 3319 | 3378 | const needed_limbs = 2 * a.len() + 1; |
| 3320 | | |
| 3321 | | if (rma.limbs.ptr == a.limbs.ptr) { |
| 3322 | | var m = try Managed.initCapacity(rma.allocator, needed_limbs); |
| 3323 | | errdefer m.deinit(); |
| 3324 | | var m_mut = m.toMutable(); |
| 3325 | | m_mut.sqrNoAlias(a.toConst(), rma.allocator); |
| 3326 | | m.setMetadata(m_mut.positive, m_mut.len); |
| 3327 | | |
| 3328 | | rma.deinit(); |
| 3329 | | rma.swap(&m); |
| 3379 | const capacity_alias = limbsAliasDistinct(rma, a); |
| 3380 | const same_buffer = rma.limbs.ptr == a.limbs.ptr; |
| 3381 | try rma.ensureAliasAwareCapacity(needed_limbs, capacity_alias); |
| 3382 | |
| 3383 | if (same_buffer) { |
| 3384 | const a_len = a.len(); |
| 3385 | const tmp = try rma.allocator.alloc(Limb, a_len); |
| 3386 | defer rma.allocator.free(tmp); |
| 3387 | @memcpy(tmp[0..a_len], a.limbs[0..a_len]); |
| 3388 | const a_const = Const{ .limbs = tmp[0..a_len], .positive = a.isPositive() }; |
| 3389 | var rma_mut = rma.toMutable(); |
| 3390 | rma_mut.sqrNoAlias(a_const, rma.allocator); |
| 3391 | rma.setMetadata(rma_mut.positive, rma_mut.len); |
| 3330 | 3392 | } else { |
| 3331 | | try rma.ensureCapacity(needed_limbs); |
| 3332 | 3393 | var rma_mut = rma.toMutable(); |
| 3333 | 3394 | rma_mut.sqrNoAlias(a.toConst(), rma.allocator); |
| 3334 | 3395 | rma.setMetadata(rma_mut.positive, rma_mut.len); |
| ... | ... | @@ -3337,21 +3398,23 @@ pub const Managed = struct { |
| 3337 | 3398 | |
| 3338 | 3399 | pub fn pow(rma: *Managed, a: *const Managed, b: u32) !void { |
| 3339 | 3400 | const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b); |
| 3401 | const capacity_alias = limbsAliasDistinct(rma, a); |
| 3402 | const same_buffer = rma.limbs.ptr == a.limbs.ptr; |
| 3340 | 3403 | |
| 3404 | try rma.ensureAliasAwareCapacity(needed_limbs, capacity_alias); |
| 3341 | 3405 | const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs); |
| 3342 | 3406 | defer rma.allocator.free(limbs_buffer); |
| 3343 | 3407 | |
| 3344 | | if (rma.limbs.ptr == a.limbs.ptr) { |
| 3345 | | var m = try Managed.initCapacity(rma.allocator, needed_limbs); |
| 3346 | | errdefer m.deinit(); |
| 3347 | | var m_mut = m.toMutable(); |
| 3348 | | m_mut.pow(a.toConst(), b, limbs_buffer); |
| 3349 | | m.setMetadata(m_mut.positive, m_mut.len); |
| 3350 | | |
| 3351 | | rma.deinit(); |
| 3352 | | rma.swap(&m); |
| 3408 | if (same_buffer) { |
| 3409 | const a_len = a.len(); |
| 3410 | const tmp = try rma.allocator.alloc(Limb, a_len); |
| 3411 | defer rma.allocator.free(tmp); |
| 3412 | @memcpy(tmp[0..a_len], a.limbs[0..a_len]); |
| 3413 | const a_const = Const{ .limbs = tmp[0..a_len], .positive = a.isPositive() }; |
| 3414 | var rma_mut = rma.toMutable(); |
| 3415 | rma_mut.pow(a_const, b, limbs_buffer); |
| 3416 | rma.setMetadata(rma_mut.positive, rma_mut.len); |
| 3353 | 3417 | } else { |
| 3354 | | try rma.ensureCapacity(needed_limbs); |
| 3355 | 3418 | var rma_mut = rma.toMutable(); |
| 3356 | 3419 | rma_mut.pow(a.toConst(), b, limbs_buffer); |
| 3357 | 3420 | rma.setMetadata(rma_mut.positive, rma_mut.len); |
| ... | ... | @@ -3361,6 +3424,7 @@ pub const Managed = struct { |
| 3361 | 3424 | /// r = ⌊√a⌋ |
| 3362 | 3425 | pub fn sqrt(rma: *Managed, a: *const Managed) !void { |
| 3363 | 3426 | const bit_count = a.bitCountAbs(); |
| 3427 | const aliased = limbsAliasDistinct(rma, a); |
| 3364 | 3428 | |
| 3365 | 3429 | if (bit_count == 0) { |
| 3366 | 3430 | try rma.set(0); |
| ... | ... | @@ -3376,7 +3440,8 @@ pub const Managed = struct { |
| 3376 | 3440 | const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs); |
| 3377 | 3441 | defer rma.allocator.free(limbs_buffer); |
| 3378 | 3442 | |
| 3379 | | try rma.ensureCapacity((a.len() - 1) / 2 + 1); |
| 3443 | const needed = (a.len() - 1) / 2 + 1; |
| 3444 | try rma.ensureAliasAwareCapacity(needed, aliased); |
| 3380 | 3445 | var m = rma.toMutable(); |
| 3381 | 3446 | m.sqrt(a.toConst(), limbs_buffer); |
| 3382 | 3447 | rma.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3384,7 +3449,9 @@ pub const Managed = struct { |
| 3384 | 3449 | |
| 3385 | 3450 | /// r = truncate(Int(signedness, bit_count), a) |
| 3386 | 3451 | pub fn truncate(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void { |
| 3387 | | try r.ensureCapacity(calcTwosCompLimbCount(bit_count)); |
| 3452 | const aliased = limbsAliasDistinct(r, a); |
| 3453 | const needed = calcTwosCompLimbCount(bit_count); |
| 3454 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3388 | 3455 | var m = r.toMutable(); |
| 3389 | 3456 | m.truncate(a.toConst(), signedness, bit_count); |
| 3390 | 3457 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3392,7 +3459,9 @@ pub const Managed = struct { |
| 3392 | 3459 | |
| 3393 | 3460 | /// r = saturate(Int(signedness, bit_count), a) |
| 3394 | 3461 | pub fn saturate(r: *Managed, a: *const Managed, signedness: Signedness, bit_count: usize) !void { |
| 3395 | | try r.ensureCapacity(calcTwosCompLimbCount(bit_count)); |
| 3462 | const aliased = limbsAliasDistinct(r, a); |
| 3463 | const needed = calcTwosCompLimbCount(bit_count); |
| 3464 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3396 | 3465 | var m = r.toMutable(); |
| 3397 | 3466 | m.saturate(a.toConst(), signedness, bit_count); |
| 3398 | 3467 | r.setMetadata(m.positive, m.len); |
| ... | ... | @@ -3401,7 +3470,9 @@ pub const Managed = struct { |
| 3401 | 3470 | /// r = @popCount(a) with 2s-complement semantics. |
| 3402 | 3471 | /// r and a may be aliases. |
| 3403 | 3472 | pub fn popCount(r: *Managed, a: *const Managed, bit_count: usize) !void { |
| 3404 | | try r.ensureCapacity(calcTwosCompLimbCount(bit_count)); |
| 3473 | const aliased = limbsAliasDistinct(r, a); |
| 3474 | const needed = calcTwosCompLimbCount(bit_count); |
| 3475 | try r.ensureAliasAwareCapacity(needed, aliased); |
| 3405 | 3476 | var m = r.toMutable(); |
| 3406 | 3477 | m.popCount(a.toConst(), bit_count); |
| 3407 | 3478 | r.setMetadata(m.positive, m.len); |