Как стать автором
Обновить

Комментарии 24

1) «заколотало», «чисельные», «додаём» — о значении некоторых перлов вашего новояза остаётся только догадываться, и то безуспешно. Установите в браузер проверку орфографии, пожалуйста. Мне больно за читателей и других форумов, в которые вы пишете, причём чаще, чем на Хабре.

2) способы проигнорировать функцию main() при выполнении программы существуют, да.

3) Вводная по метапрограммированию — тоже любопытна.
извините, исправил.
1) «чисельные», «додаём» — это все кальки с украинской математической терминологии, автор украиноязычен и слушал лекции по матану только на украинском языке. Никакого новояза.
Читать Майерса и Александреску это хорошо. Но я бы за такие развлечения в коде проекта без явно указанной необходимости в таком коде, отрывал руки без права пришития обратно.

Шаблоны очень сложны в отладке и сообщения об ошибках выдаваемые gcc на шаблонах не страдают информативностью. Подобный код хорош, когда он написан раз и его трогать больше не надо. Или когда действительно встаёт задача какие-то вещи для оптимизации вынести в compile-time. В остальном — такой код — лютое нечитабельное и неподдерживаемое говно.

Я не говорю про то, что шаблоны это плохо, но вот к метапрограммированию на них надо относиться очень аккуратно.
Как хорошо, что благодаря constexpr, все эти танцы с шаблонами вскоре уйдут в прошлое.
Поддерживаю. Статья хороший пример мощи шаблонов и отличный стимул перейти на стандарт 11 года.
Ну что вы, теперь так e вычисляить уже не модно!
Вот он, новый способ:

#include <iostream>

constexpr int factorial(int n)
{
    return n > 1? factorial(n-1) * n : 1;
}

constexpr double cpow(double v, int n)
{
    return n ==0? 1: v * cpow(v, n-1);
}

constexpr double factor(double v, int n)
{
    return cpow(v, n) / factorial(n);
}

constexpr double sum(double v, int n, int max)
{
    return factor(v, n) + (max == n? 0: sum(v, n + 1, max));
}

constexpr double cexp(double v, int accuracy)
{
    return sum(v, 0, accuracy);
}

int main(int argc, const char** argv) 
{
    constexpr double e = cexp(1, 8);
    std::cout.precision(15);
    std::cout << e << "\n";
}

И функцию Аккермана? ;-)
НЛО прилетело и опубликовало эту надпись здесь
От непосредственного вычисления значения факториала можно избавиться путем выражения последующего члена ряда Тейлора через предыдущий. Насколько я помню, могу ошибаться, fpu так и вычисляет тригонометрию.
Насчет тригонометрии — вроде давно таблицы Брадиса во флэше записаны, вычислять только поправку нужно.
НЛО прилетело и опубликовало эту надпись здесь
У вас неправильная сумма ряда. Вот результат на Maple:

2.7182818284590452353602874713526624977572470937000 — точное значение:
2.7182818284590452353602874713526624976385970411899 — Ряд Тейлора до 1/32!

Цепную дробь пока не посчитал.
2.7182818284590452353602874713558030927124686274627 — цепная дробь (33 члена разложения)
НЛО прилетело и опубликовало эту надпись здесь
Зато если считать в рациональных числах (не сокращая их) и ограничивать числитель и знаменатель какой-нибудь константой, то цепные дроби дадут почти вдвое лучший результат по числу знаков. Так, если взять ограничение 2^32, то цепную дробь можно считать до [...,14,1,1], и получается 848456353/312129649 (17 верных знаков). Ряд Тейлора считается до 1/12!, и получается 1302061345/479001600 (9 верных знаков). Удивительно, что сумма обратных факториалов иногда сокращается.
— сейчас я покажу вам особую, шаблонную магию!
— в рот мне ноги! нет-нет-нет, александреску, немедленно верни все как было!!!
Не обращайте внимания на граммар-нази и лиц, лишенных чувства юмора. Статья здоровская! Только напишите в начале крупными буквами «Не пытайтесь повторить это в реальных проектах»:)
Почему статья не в хабе «Ненормальное программирование». Требую перенести!
Шаблоны в С++ это как подъязык в языке. Т.е. сейчас вы решили задачу поиска экспоненты на специфическом языке, а не на С++. Статья хорошая в плане того, что бы взять на заметку и когда приспичит писать шаблоны, посмотреть и вспомнить как можно извратиться :)
Думаю, именно из-за такого безобразия в метапрограммировании на шаблонах Александреску и сбежал в D.
Compile-time аналог на D (используя цепную дробь):
module ecompute;

import std.stdio;

// Вариант 1, используя CTFE
static double computeE1(int n)
{
	double innerCompute(int i, int m)
	{
		if(m <= 0)
		{
			return 0.0;
		}
		return 1.0/(
			    1.0 + 1.0/(
			      i + 1.0/(
			    1.0 + innerCompute(i + 2, m - 1))));
	}
	return 2.0 + innerCompute(2, n);
}

// Вариант 2, олдскул
template computeE2(int n)
{
	private template innerCompute(int i, int m)
	{
		static if(m <= 0)
		{
			enum innerCompute = 0.0;
		} else
		{
			enum innerCompute = 1.0/(
					1.0 + 1.0/(
					  i + 1.0/(
					1.0 + innerCompute!(i + 2, m - 1))));
		}
	}
	enum computeE2 = 2.0 + innerCompute!(2, n);
}

void main()
{
	// Вариант 1
	static immutable e1 = computeE1(20);
	pragma(msg, e1);
	printf("Case 1, e = %1.20f \n",e1);

	// Вариант 2
	static immutable e2 = computeE2!(20);
	pragma(msg, e2);
	printf("Case 2, e = %1.20f \n",e2);
}

D упрощает compile-time программирование, а люди идут в своих извращениях дальше: compile-time raytracer.
Я тоже около 15 лет думал, что пишется «substract». Так и писал. А оказалось — «subtract». Видимо, это какое-то популярное заблуждение.
Неа, и то и то правильно. Но substract — устаревшая форма.
en.wiktionary.org/wiki/substract
english.stackexchange.com/questions/3640/is-substract-versus-subtract-a-proper-word
Сейчас предпочтительнее юзать subtract. А вот почему многие(и я, в том числе) юзают именно substract — тот еще вопрос.
Возможно стоит добавить следующие ссылки:
Template metaprogramming на википедии
Boost.MPL — фреймворк для создания программ, которые производят вычисления во время компиляции с помощью шаблонов.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации