btvn.vn
Tìm kiếm Đăng nhập

Lũy thừa nhanh bằng chia để trị

Lưu trên thiết bị này
Chuyên đề lựa chọn CS: Chia để trị · Chọn bài khác

Tính nửa số mũ rồi bình phương

Xét $a\ne0$ và số nguyên n≥0. Cơ sở là $a^0=1$. Nếu n=2k thì $a^n=(a^k)^2$; nếu n=2k+1 thì $a^n=a(a^k)^2$. Vì vậy chỉ cần tính một lần $b=a^{\lfloor n/2\rfloor}$, rồi dùng b ở cả hai thừa số. Việc lưu b giúp tránh tính lại cùng một bài toán nhỏ.

Một lời gọi nhỏ ở mỗi mức

```python def power_fast(a, n): if n == 0: return 1 b = power_fast(a, n // 2) if n % 2 == 0: return b * b return a * b * b ``` Với a=2,n=13, các lời gọi đi qua số mũ 13,6,3,1,0. Khi trả về: | n | b đã có | Kết quả | |---|---|---| | 0 | Cơ sở | 1 | | 1 | 1 | 2×1×1=2 | | 3 | 2 | 2×2×2=8 | | 6 | 8 | 8×8=64 | | 13 | 64 | 2×64×64=8192 | Nhánh chẵn có một phép nhân; nhánh lẻ có hai phép nhân trong biểu thức a*b*b. Với đoạn mã đang hiển thị, ví dụ này có 7 phép nhân, kể cả các phép nhân với 1 ở n=1.

Đếm đúng cách cài đặt đang xét

Bản nhân lần lượt khởi đầu p=1 rồi nhân p với a đúng n lần, nên có n phép nhân; với n=13 là 13 lần. Khi tính tay có thể bắt đầu ngay từ a và bỏ một phép nhân với 1, nên số đếm khác với mã khởi đầu p=1. Theo mô hình của sách coi mỗi phép tính cơ bản có chi phí hằng số, bản nhanh chỉ có một bài toán nhỏ với số mũ n//2 và không quá hai phép nhân để kết hợp. Số mức tăng theo $\log n$, cho bậc $O(\log n)$ thay vì $O(n)$ của bản nhân lần lượt. Số đếm ấy không tự là số mili giây thực chạy. Nếu viết hai lời gọi power_fast(a,n//2) riêng để nhân với nhau, cùng kết quả nhỏ bị tính lại; đó không còn là cách lưu b đang phân tích.

Bài luyện

Với hàm power_fast trong bài, power_fast(2,13) trả về bao nhiêu?
Chọn một đáp án

Bài luyện

Vì sao cần lưu b=power_fast(a,n//2) rồi dùng b*b?
Chọn một đáp án

Bài luyện

Với a=−3 và n=0, cơ sở của power_fast trả gì?
Chọn một đáp án

Đang học