# -*- coding: utf-8 -*- """Демо: разбиение работы на куски не должно менять результат. Запуск из корня курса: python lab01_sequential/examples/02_split_check_demo.py Ключевая идея курса: задача формулируется как split -> kernel -> combine -> checksum. Разбиение — это подготовка к параллелизму: последовательный запуск кусков обязан давать тот же checksum, что и один большой кусок. """ import os import sys sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from common.tasks import TASKS, smoke_params def run(task_name: str, parts: int): """Последовательный запуск задачи из `parts` кусков.""" task = TASKS[task_name] params = smoke_params(task_name) data = task["build"](params) chunks = task["split"](data, parts) partials = [task["kernel"](ch) for ch in chunks] raw = task["combine"](partials) return task["checksum"](raw) def main(): print(f"{'задача':<12} {'parts=1':>18} {'parts=2':>18} {'parts=4':>18} совпадает") for name in ("pi_mc", "integrate", "nqueens", "blur", "hashing"): v1 = run(name, 1) v2 = run(name, 2) v4 = run(name, 4) # float-результаты (π, интеграл) сравниваем с допуском: при разбиении # меняется порядок суммирования, меняются последние биты мантиссы def same(a, b): if isinstance(a, float): return abs(a - b) <= 1e-6 * max(1.0, abs(a)) return a == b same12 = same(v1, v2) same14 = same(v1, v4) marker = "True" if (same12 and same14) else "False <-- ОШИБКА" print(f"{name:<12} {v1:>18.6f} {v2:>18.6f} {v4:>18.6f} {marker}") print("\nЕсли checksum зависит от разбиения — параллельная версия будет") print("давать «случайный» результат. Это ошибка, а не особенность.") print("(Float-задачи сравниваются с допуском — см. код демо.)") if __name__ == "__main__": main()