Формула Белларда всегда дает 3,14506

Я работал над простой программой на C++ для аппроксимации числа Пи по формуле Белларда. Независимо от того, какое количество цифр он пытается вычислить, в результате получается число 3,145063.

Я попытался изменить его с хранения с плавающей запятой на двойную, потому что думал, что это может быть просто округление, чтобы соответствовать меньшему типу данных, но это все равно не работает.

Вот мой код:

#include <iostream>
#include <cmath>

double approximate(int digits) {
    double summed = 0;
    for (int n = 0; n < digits; n++) {
        summed += (pow(-1, n) / pow(2, n * 10)) * ((-(pow(2, 5)) / (4 * n + 1)) - (1 / (4 * n + 3)) + (pow(2, 8) / (10 * n + 1)) - (pow(2, 6) / (10 * n + 3)) - (pow(2, 2) / (10 * n + 5)) - (pow(2, 2) / (10 * n + 7)) + (1 / (10 * n + 9)));
    }
    return (1 / pow(2, 6)) * summed;
}

int main() {
    std::cout << "How many digits?: ";
    std::string its;
    std::getline(std::cin, its);
    std::string approx = std::to_string(approximate(std::stoi(its)));
    std::cout << approx << std::endl;
}

Похоже, вам, возможно, придется научиться использовать отладчик для пошагового выполнения кода. С помощью хорошего отладчика вы можете выполнять программу построчно и видеть, где она отклоняется от ожидаемого. Это важный инструмент, если вы собираетесь заниматься программированием. Дальнейшее чтение: Как отлаживать небольшие программы и Руководство по отладке

NathanOliver 07.05.2024 02:50
summed += -- Вместо этой ужасно длинной строки кода разбейте ее на несколько строк, чтобы увидеть, какое вычисление не соответствует вашим ожиданиям. И да, используйте отладчик.
PaulMcKenzie 07.05.2024 02:51
1 / (10 * n + 9) — Это целочисленное деление. Целое число, разделенное на целое число, даст вам целое число. Но опять же, если бы вы нарушили эту линию, вы бы столкнулись с этой проблемой.
PaulMcKenzie 07.05.2024 02:53

Примечание: компиляторы становятся умнее и могут уловить эту переборку, но pow(-1, n) переворачивать знаковый бит очень дорого, если компилятор не поймет это. pow — это отвратительная штука, предназначенная для борьбы с плохими матерями <ругательство удалено>, такими как вычисление числа Пи в степени е. Если вы немного переворачиваете pow(-1, n), немного двигаетесь pow(2,n) или выполняете простое возведение в квадрат pow(x,2), вы можете обнаружить, что программа выполняет гораздо больше работы, чем использование справочной таблицы, битового сдвига или умножения.

user4581301 07.05.2024 03:07

Примечание: опять же, компиляторы становятся умнее и могут заметить, что pow(2, 5) никогда не меняется, и кэшировать результат или, возможно, даже вычислить его во время компиляции и превратить в константу. Но проверь все равно.

user4581301 07.05.2024 03:10

И не забудьте проверить ввод на наличие ошибок: godbolt.org/z/jf6xv4nqT

user4581301 07.05.2024 03:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
122
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как уже упоминалось, если бы вы разбили строку на несколько операторов, вы бы увидели, что выполняете целочисленное деление вместо деления с плавающей запятой.

(1 / (4 * n + 3)) и (1 / (10 * n + 9))

не верны. Простое исправление состоит в том, чтобы использовать 1.0, чтобы принудительно выполнить деление с плавающей запятой:

#include <iostream>
#include <cmath>

double approximate(int digits) {
    double summed = 0;
    for (int n = 0; n < digits; n++) {
        summed += (pow(-1, n) / pow(2, n * 10)) * 
                  ((-(pow(2, 5)) / (4 * n + 1)) - (1.0 / (4 * n + 3)) + // <-- 1.0
                  (pow(2, 8) / (10 * n + 1)) - 
                  (pow(2, 6) / (10 * n + 3)) - 
                  (pow(2, 2) / (10 * n + 5)) - 
                  (pow(2, 2) / (10 * n + 7)) + (1.0 / (10 * n + 9))); // <-- 1.0
    }
    return (1 / pow(2, 6)) * summed;
}

int main() {
    std::string approx = std::to_string(approximate(10));
    std::cout << approx << std::endl;
}

Выход:

3.141593

Другие вещи в вашем коде, которые также можно улучшить, а именно, вызовы pow. Вы знаете, что pow(2,2), pow(2,5), pow(2,8), pow(2,6), (1.0 / pow(2,6)), etc. are constants. They do not be need to be computed each and every time the дляloop iterates, or at theточки возврата. Просто создайте эти константы с плавающей запятой и используйте их.


Редактировать:

Вот версия вашего кода для времени компиляции, которая может вычислять с точностью до 6 цифр.

Обратите внимание, что выходные данные сборки нигде не содержат следов вызова функции approximate, поскольку все значение было вычислено во время компиляции.

Спасибо, это работает. Единственная проблема заключается в том, что результат, кажется, остается неизменным независимо от количества введенных цифр, но я думаю, что это совсем другая проблема.

Jake StBu 07.05.2024 03:23

@JakeStBu Помните, что алгоритм не вычисляет по одной цифре за раз, а гарантирует, что N цифр верны. Примерно после N=5 вы не увидите никакой разницы в вычислении первых 10 или около того цифр.

Dúthomhas 07.05.2024 04:04

Другие вопросы по теме