LINUX.ORG.RU

Метапрограммирование - проблемы и пути их решения.

 , ,


12

6

Пичал я тут на днях токенайзел для C++-кода, но всё это меня добило я решил поделится.

Проблема - мне надо было вычислять сложные значения для таблицы в компилтайме, да можно на сишке сделать через жопу(енумы) и макросы, но мне стало лень. Да можно сгинерить, но мне тоже лень.

Шблонную магию плюсов я не люблю, ибо она ущербна чуть более, чем полностью и тут я вспомнил, что оказывается в плюсах хотели ввести компилтайм функции, аля constexpr и подумалось мне - во, плюсы затащат и как всегда я в очередной раз убедился в ущербности плюсов и так и не понял логики тех, кто это запилил.

Чтобы не быть голословным пишем что-то типа

constexpr uint64_t f(uint64_t a, uint64_t b) {
  return a + b; 
}
Всё ок, но пишем что-то сложнее, аля:

uint64_t m[] = {0, 1, 2, 3, 4};
constexpr uint64_t f(uint64_t a, uint64_t b) {
  return m[a] + m[b]; 
}

Бида( или это моё неосиляторство плюсов?), дак зачем они запилили эту фичу, если она может лишь галимую примитивщину? Шаблоны ещё ущербней. В чем приемущество? Зачем?

А теперь у меня вопрос к вам, уважаемы батьки и отцы - что мне делать? Я хочу запонять массивы написав генератор, причем и в компилтайме тоже. Я хочу юзать libc, я хочу всё, а у меня нет ничего, почему?

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

У меня есть 3 пути: терпеть, пилить свой язык и конпелятор самому( что долго и нудно) и ваш совет.

Ответ на: комментарий от www_linux_org_ru

gcc-4.4.5, -O3;-)

Я убедительно всех прошу дождаться решения от ТС-а. Ежели кому вот прямо щас неймется - давайте мыло, напишу ху из ху.

PS Я не говорил, что использую именно этот код. Этот код лишь показывает, что именно вычисляется. Мне очень хочется увидеть, как ТС хвалившийся всех-порвать-на-unit64_t сможет реализовать эту простейшую для флоатинг-пойнт задачу хотя бы с той же производительностью, что получилась у меня.

Знание - сила!!!111

AIv ★★★★★
()
Последнее исправление: AIv (всего исправлений: 1)
Ответ на: комментарий от superhackkiller1997

Во-первых, ты забыл тройку, но это значения не имеет.

Во-вторых, покажи, как из твоего инта на пи получить пи квадрат, то есть пи*пи.

В-третьих, выпиши, пожалуйста, в твоих интах приближение числа 1/3=0.(3).

aedeph_ ★★
()
Ответ на: комментарий от AIv

Я убедительно всех прошу дождаться решения от ТС-а. <...> Я не говорил, что использую именно этот код.

я лично ничего подсказывать ТС не собираюсь, но к тебе просьба — описать задачу чуть точнее

я, например, понял ее совсем по другому, примерно так: выкатить набросок с++ библиотеки, которая позволит использовать _*именно этот*_ код (возможно, с минимальными доработками) для получения не менее точного численного результата через целочисленную арифметику за сопоставимое время

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

вот он че-то там вроде рассказывал про свои якобы офигенные скиллы программирования и оптимизации, поэтому нужно его грузить именно этим, а не полуменеджерской деятельностью типа «уточнить постановку задачи»

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от www_linux_org_ru

Присмотрись внимательней — там очень известный ряд Тейлора одной очень известной функции :) Его можно ускорить переписав на SSE* интринсиками, например (тогда будет вплоть до ~ 20 тактов). Но от ТС требуется просто реализовать эту функцию _как угодно_, но на целых (раз он так хочет) — на интервале [-10, 10], учитывая промежуточные значения аргументов (-2.311 и 3.978, например) с не меньшей точностью результатов (~ 10 знаков).

quasimoto ★★★★
()
Ответ на: комментарий от www_linux_org_ru

Царь аналитика от царя.

Вопервых, раз он заикнулся о точности - значит он шаманил с n, ибо после 20 точность счёта уменьшается(он говорил о каких-то 10знааков, но половина его знаков - мусор), а после 40 дак вообще она уйдёт в 0.

Т.е. смысла юзать n=100 нет. Смысла юзать умножение в циакле для norm нет - он должен был осилить таблички.

Банальным выпиливаеним n - там уже остётся в районе 20-40итераций.

Можно поколдавать со степенями х. Как уже ниже пациент написал те же ссе.

Я посижу сегодня днём - погляжу.

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

superhackkiller1997
() автор топика
Ответ на: комментарий от quasimoto

Присмотрись внимательней — там очень известный ряд Тейлора одной очень известной функции :)

присматриваться не надо — это очень трудно не заметить :-)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от superhackkiller1997

он говорил о каких-то 10знааков, но половина его знаков - мусор

У той функции при N = 100 выхлоп на интервале получается такой:

-9		0.0001234098040866795
-8		0.0003354626279025119
-7		0.0009118819655545169
-6		0.002478752176666358
-5		0.006737946999085469
...
5		148.4131591025766
6		403.4287934927351
7		1096.633158428458
8		2980.957987041728
9		8103.083927575384

желаемый результат:

-9		0.0001234098040866795494976366907300338260721...
-8		0.0003354626279025118388213891257808610193109...
-7		0.0009118819655545162080031360844092826264737...
-6		0.0024787521766663584230451674308166678915064...
-5		0.0067379469990854670966360484231484242488495...
...
5		148.41315910257660342111558004055227962348766...
6		403.42879349273512260838718054338827960589989...
7		1096.6331584284585992637202382881214324422191...
8		2980.9579870417282747435920994528886737559679...
9		8103.0839275753840077099966894327599650114760...

Никакого мусора. В центре интервала и во всех промежуточных значениях куда хватает разрешения double всё, разумеется, тоже хорошо.

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от superhackkiller1997

Виды обработки, виды, глупое, анскильное ты лалка. Получают деталь с допусками в микроны ЛИШЬ ПОЛИРОВКОЙ.

это, деточка, шлифованием зовут. Если ты, не доверяешь МАМИ, то подскажи более авторитетный источник. А то я теряюсь в догадках…

ЭТО СВЕРЛЕНИЕ, ПРИЧЕМ МНОГОПРОХОДНОЕ И ПОСЛЕДНИЙ ЭТАП ДАЛЕКО НЕ СВЕРЛО. У СВЕРЛЕНИЯ ТОЧНОСТЬ В ТЫСЯЧИ РАЗ БОЛЬШЕ, ЧЕМ У РЕЗА.

О сколько нам открытий чудных… Сверление не сверлом — это сильно. А что такое «РЕЗ»?

Повторяю - точность это идеальная точность, а не допуск. Когда ты этой помёшь.

ну как объяснишь, что такое «идеальная точность», так сразу и пойму. А то мы этого ещё не проходили.

Чё ты несёшь? Флоат - это тип, глупая ты лалка, а флоатпоинт. Дак 64битно целое число в 3раза точнее твоего флоата, не?

float это один из типов, которые умеет SSE. int64 — это другой тип, который тоже умеет SSE. Так вот, float считается на SSE вдвое быстрее int64. Или есть какой-то другой метод, о котором я не знаю?

И да, у float точность ВСЕГДА 23 бита, а вот у int точность зависит от того, сколько битов лежит в этом int. Если там 1 бит, то и точность будет ровно 1 бит. А вот если записать 1 бит в float (например записать единицу), то float автоматически расширит этот 1 бит на 23 значимых бита, как раз для того, что-бы точность не терялась.

99.9999% вычислений влезет в uint64_t, но не влезет во флоат, а влезет в дабл.

влезет только РЕЗУЛЬТАТ, да и то, ТОЛЬКО в том случае, если ты будешь считать в каких-нибудь нанометрах и нанограммах. При этом промежуточные результаты ВЫЛЕЗУТ из int.

Упоролся? Иди осиль целые числа и не неси херню. Умнож своё число на мильяр, потом дели. Ибо в uint64_t надо считать не целыми частями, а 1/100000000 представленной как один. Твой флоат делает это автоматом.

ЯННП

покажи свой код деления int'ов.

Не любое, а для которого во флоате есть диапазон. 3333333 - ты запишешь, выше у тебя случится фейл. и 333333333 == 333333339 и т.п.

у меня всё будет хорошо, а вот фейлишься сейчас ты.

float t = 0.987654321; float t1 = 0.987654349;

t == t1

ты упоролся. Этой командой ты разделил на ноль. И получил хрень.

и да, разница t-t1 меньше 1/2²³, потому-то результат float может быть нулём. А может и не быть. Зависит от реализации и погоды на Марсе.

А ты — будущий упоротый говнокодер, и лучше тебе заняться чем-то более полезным, чем делить на ноль в CS.

drBatty ★★
()
Ответ на: комментарий от quasimoto

Теперь умньш N до 50 - удивись. Числа уже заходят за предел точности дабла и гинерят мусор, который ты потом выкидываешь.

 
5.
147.41315910257657151305//выхлоп твоей функции
147.41315910257660342091//написал на bc 100n
147.41315910257660342091//bc 50n
147.41315910257657151305//выхлоп твоей 50n
147.41315910257660342090//bc 40n
147.41315910257657151305//выхлоп твоей 40n
147.41315910257242185407//bc 30n
147.41315910257239352177//выхлоп твоей 30n

Т.е. после 40n оно гинерит уже мусор.

superhackkiller1997
() автор топика
Ответ на: комментарий от tailgunner

Что порядок вычисления, если и влияет на что-то, то на доли копейки

откуда такая уверенность для ВСЕХ процессоров?

и что в 99% процентов вызовов оптимизатор может поменять порядок вычислений, не меняя семантики программы.

а в 1% не сможет, и напишет: «Не смогла. Пожалуйста, переставьте местами 5 и 6й параметр в функции в строке foo.c:65721»?

PS: не забывай, что функция вполне может находится в другом модули трансляции, и что ей критично, что в памяти будет записано x,y,z, а не наоборот. А в CPU может и не быть предусмотрено _быстрого_ способа заталкивания в стек в произвольном порядке. И если ты вызываешь foo(i++,i++,i++), то компилятору придётся делать две лишних временных переменных, дабы обеспечить порядок слева-направо, если стек работает справа-налево, как например в «малораспространённой» архитектуре x86. Да и в 95% других архитектур именно таки LIFO.

Ты действительно предлагаешь делать лишний оверхед для корректности работы быдлокода foo(i++,i++,i++) ?

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

https://github.com/mortdeus/legacy-cc - почитай это, ритчи писал тот ещё фуфлокод. Поэтому сишка и получилась немного кривой.

где ты был, пока он это писал? Меня в тот момент ещё не было, я через 3 года родился.

drBatty ★★
()
Ответ на: комментарий от tailgunner

Насколько я понимаю идею местного вундеркинда, предлагается считать в нанолитрах, нанометракх, наносекундак (или пико-). Точности int64_t всё равно хватит для всех практических задач.

Да, но там есть одна тонкость: чем меньше воды в баке, тем меньше её напор, и антипереполнение на последних итерациях (даже если у него их будет >5) ему гарантировано. И то, это только при грамотном и внимательном кодировании. Можно конечно нагуглить решение диф. уравнения, но это ему явно не осилить, а даже если он и осилит, я буду удивлён, если он напишет вычисление exp(x) для своих uint64 ☺

drBatty ★★
()
Ответ на: комментарий от drBatty

это, деточка, шлифованием зовут. Если ты, не доверяешь МАМИ, то подскажи более авторитетный источник. А то я теряюсь в догадках…

Да мне похрен как это завётся.

О сколько нам открытий чудных… Сверление не сверлом — это сильно. А что такое «РЕЗ»?

Там где-то написано, что первый этап не сверло? Возможно и не сверло - это важно, а важно лишь то, что последний не сверло. Какие ещё инструменты есть - гугл тебе в помощь.

ну как объяснишь, что такое «идеальная точность», так сразу и пойму. А то мы этого ещё не проходили.

Гляди мой пост выше - поймёшь.

float это один из типов, которые умеет SSE. int64 — это другой тип, который тоже умеет SSE. Так вот, float считается на SSE вдвое быстрее int64. Или есть какой-то другой метод, о котором я не знаю?

Ты что несёшь, глупышка? Чего вдвое быстрее, какой int64?

бери 32битный целый тип, а не 64битдый. Есть метод - это не нести херню.

И да, у float точность ВСЕГДА 23 бита, а вот у int точность зависит от того, сколько битов лежит в этом int. Если там 1 бит, то и точность будет ровно 1 бит. А вот если записать 1 бит в float (например записать единицу), то float автоматически расширит этот 1 бит на 23 значимых бита, как раз для того, что-бы точность не терялась.

Глупая лалка, почему ты бумаешь, что единица в инте записывается 1битом? Они будет записываться столькими битами, сколько я захочу. Хоть 30, хоть 40.

влезет только РЕЗУЛЬТАТ, да и то, ТОЛЬКО в том случае, если ты будешь считать в каких-нибудь нанометрах и нанограммах. При этом промежуточные результаты ВЫЛЕЗУТ из int.

Упоролся? При ущеобанском счёты детсадовсца типа тебя - да вылезут, а при нормальном нет.

покажи свой код деления int'ов.

Ты читаешь еденицами, которые равны 1/10000000 еденицы реальной - тебе это так трудно понять?

Еденица реальная - это 10000000 псевдоеденицы, которые запмсываются в инт как 10000000. И ты считаешь в псевдоединицах, что тебе тут не ясно?

у меня всё будет хорошо, а вот фейлишься сейчас ты.

Реально? Хорошо? Ты понимаешь, что для чисел с точностью более 7 знаков у твоего float НЕТ реальных представлений чисел.

ты упоролся. Этой командой ты разделил на ноль. И получил хрень.

Я не поделил на ноль - поделил на ноль ты своим детсадовским знанием битиков. Это коммендой я доказал, что представление этих чисел ОДИНАКОГО, а это значит, что сложение разных чисел будет давать ОДИН результат, что противоречит МИРУ. Поэтому ТВОЙ ФЛОАТ И РАБОТАЕТ. ОН ТУПО ОТКИДЫВАЕТ РАЗРЯДЫ.

и да, разница t-t1 меньше 1/2²³, потому-то результат float может быть нулём. А может и не быть. Зависит от реализации и погоды на Марсе.

ТАК БУДЕТ ВСЕГДА, ибо ДЛЯ ЧИСЕЛ С КОЛ-ВОМ РАЗРЯДОМ БОЛЬШЕ 7 У ФЛОАТА НЕТ ПРЕДСТАВЛЕНИЯ. ОН ОТКИДЫВАЕТ ЛИШНИЕ РАЗРЯДЫ И ВПИЛИВАЕТ ТУДА МУСОР.

А ты — будущий упоротый говнокодер, и лучше тебе заняться чем-то более полезным, чем делить на ноль в CS.

Мнение анскильных неосиляторов не интересует.

superhackkiller1997
() автор топика
Ответ на: комментарий от drBatty

Твоё жалкое балабольство не знает границ. Твой мозгопроцесс слишком примитивен и жалок.

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

Т.е. расчёт твоей задачи с напором менее даже литра в минуту не имеет смысла, ибо он не возможен в реальном мире.

Это показыват жалкость и узость мышления мышления горестудентов и ущербность матмодели относительно реального мира.

superhackkiller1997
() автор топика
Ответ на: комментарий от AIv

Я убедительно всех прошу дождаться решения от ТС-а

ты столько не проживёшь.

drBatty ★★
()
Ответ на: комментарий от drBatty

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

Это тебе пример, почему ритчи не запилил идеальную сишку.

superhackkiller1997
() автор топика
Ответ на: комментарий от beastie

Да я стараюсь. Он слишком токсичен.

Слова филиппа филипповича есть ересь вселенских масштабов, ибо из-за таких вот норм поведения образование на днище морском.

Если твоя ТЗ правильней - покажи это, укажи на сливмоменты собеседника и т.п. А если ты сливаешься как дитё и пытаешься выплыть на аргументации, аля «я закончил вуз я априори лучшу всё понимаю» - это фейспалм.

Соцстатусы - это порочно и были заимствованы из стандноподчиненной модели поведения зверья. И для какаго-то там развития обвещества не применимы в принципе.

superhackkiller1997
() автор топика
Ответ на: комментарий от superhackkiller1997

Плюс да, пациент боится мне намекнуть, темнит и т.п.

он не должен тебе намекать *как* делать твою работу

другое дело, что хорошо бы он сказал, *что* он от тебя хочет — тут я конечно за него говорить не могу, но предположу, что ты код можешь переписывать как угодно, но результат функции получить с точностью не хуже, чем у него на интервале -10 <= x <=10; зрители ждут, как ты проявишь свои способности к оптимизации, ускорив вычисления

и да — тут точно не будет бугурта по поводу того, что ты сделал что-то по своему, а не по Гениальной Методике — все зависит от количества тактов, которые тебе потребуются, а не от Точного Выполнения Указаний Преподавателя Вуза

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 3)
Ответ на: комментарий от drBatty

а даже если он и осилит, я буду удивлён, если он напишет вычисление exp(x) для своих uint64 ☺

после того, как ТС с треском сольется, это напишу я (да, на инт64) — ниче сложного там нет

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от superhackkiller1997

Т.е. после 40n оно гинерит уже мусор.

float из SSE2 работает и для n == 50

#include <stdio.h>

float sh1(float x)
{
	float xn = 1.0;
	float res = 0.0;
	float norm = 1.0;
	int n;
	for(n = 1; n < 50; n++)
	{
		norm *= n;
		xn *= x;
		res += xn / norm;
	}
	return res;
}

int main(int argc, char *argv[])
{
	float j;
	for(j = -5.0; j < 5.5; j += 1.0)
	{
		float x = j;
		printf("x: %f, res: %f\n",
				x,
				sh1(x));
	}
	return 0;
}
$ gcc -Wall -O3 sh.c && ./a.out 
x: -5.000000, res: -0.993262
x: -4.000000, res: -0.981685
x: -3.000000, res: -0.950213
x: -2.000000, res: -0.864665
x: -1.000000, res: -0.632120
x: 0.000000, res: 0.000000
x: 1.000000, res: 1.718282
x: 2.000000, res: 6.389057
x: 3.000000, res: 19.085539
x: 4.000000, res: 53.598152
x: 5.000000, res: 147.413177

# основной цикл
  400500:       0f 57 c9                xorps  xmm1,xmm1
  400503:       b8 01 00 00 00          mov    eax,0x1
  400508:       0f 28 d5                movaps xmm2,xmm5
  40050b:       0f 28 c5                movaps xmm0,xmm5
  40050e:       66 90                   xchg   ax,ax
  400510:       f3 0f 2a d8             cvtsi2ss xmm3,eax
  400514:       f3 0f 59 d4             mulss  xmm2,xmm4
  400518:       83 c0 01                add    eax,0x1
  40051b:       83 f8 32                cmp    eax,0x32
  40051e:       f3 0f 59 c3             mulss  xmm0,xmm3
  400522:       0f 28 da                movaps xmm3,xmm2
  400525:       f3 0f 5e d8             divss  xmm3,xmm0
  400529:       f3 0f 58 cb             addss  xmm1,xmm3
  40052d:       75 e1                   jne    400510 <main+0x30>
  40052f:       0f 14 e4                unpcklps xmm4,xmm4
  400532:       bf ec 07 40 00          mov    edi,0x4007ec
  400537:       0f 14 c9                unpcklps xmm1,xmm1
  40053a:       b8 02 00 00 00          mov    eax,0x2
  40053f:       f3 0f 11 6c 24 0c       movss  DWORD PTR [rsp+0xc],xmm5
  400545:       0f 5a c4                cvtps2pd xmm0,xmm4
  400548:       0f 5a c9                cvtps2pd xmm1,xmm1
  40054b:       f3 0f 11 64 24 08       movss  DWORD PTR [rsp+0x8],xmm4
  400551:       e8 5a ff ff ff          call   4004b0 <printf@plt>
  400556:       f3 0f 10 64 24 08       movss  xmm4,DWORD PTR [rsp+0x8]
  40055c:       83 eb 01                sub    ebx,0x1
  40055f:       f3 0f 10 6c 24 0c       movss  xmm5,DWORD PTR [rsp+0xc]
  400565:       f3 0f 58 e5             addss  xmm4,xmm5
  400569:       75 95                   jne    400500 <main+0x20>
drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Точность дабла тут ни при чём — увеличением N получаем улучшение аппроксимации — если ты посмотришь на значения разницы добавляемой к res в for, то увидишь, что она всё меньше по мере роста n, так что N нужно стараться держать как можно бОльшим, но чтобы не получить в итоге nan:

    double xn = 1., nf = 1., d = 1., res = 0.;
    for (int n = 0; d > 0.; ++n, res += d = (xn *= x) / (nf *= n));
    return res;

тут без N и до максимальной точности даблов (нечего уже прибавлять).

То есть если ты берешь маленькое N, то просто сильно не добираешь до аналитических значений, так как пропускаешь значимые слагаемые сходящегося ряда.

Насчёт bc — оно тут не нужно, есть единственный точный ряд значений (аналитический) который я привёл вторым листингом выше — вот к нему нужно приближаться.

quasimoto ★★★★
()
Ответ на: комментарий от superhackkiller1997

Ты изобрёл кривой fixed point тип? Это вещь науке известная, в финансовых расчётах в основном используется.

PolarFox ★★★★★
()
Ответ на: комментарий от superhackkiller1997

МАМИ

Да мне похрен как это завётся.

это конечно сильный аргумент. Я опять слился, засчитывай.

Там где-то написано, что первый этап не сверло? Возможно и не сверло - это важно, а важно лишь то, что последний не сверло. Какие ещё инструменты есть - гугл тебе в помощь.

зачем мне гугл. Я и без тебя знаю, чем шлифуют. Жаль, что ты этого не знаешь.

ну как объяснишь, что такое «идеальная точность», так сразу и пойму. А то мы этого ещё не проходили.

Гляди мой пост выше - поймёшь.

ЯННП.

Ты что несёшь, глупышка? Чего вдвое быстрее, какой int64?

откуда я знаю, на какой int64 ты так усиленно фапаешь?

Глупая лалка, почему ты бумаешь, что единица в инте записывается 1битом? Они будет записываться столькими битами, сколько я захочу. Хоть 30, хоть 40.

только в твоих мечтах. Ибо твоего кода ещё НИКТО не видел.

влезет только РЕЗУЛЬТАТ, да и то, ТОЛЬКО в том случае, если ты будешь считать в каких-нибудь нанометрах и нанограммах. При этом промежуточные результаты ВЫЛЕЗУТ из int.

Упоролся? При ущеобанском счёты детсадовсца типа тебя - да вылезут, а при нормальном нет.

весь ЛОР, затаил дыхание, в предвкушении НОРМАЛЬНОГО кода, а не как обычно.

Ты читаешь еденицами, которые равны 1/10000000 еденицы реальной - тебе это так трудно понять?

да, трудно. Я понимаю, что значит

int x = 1;
но что значит
int x = 1/10000000;
мне непонятно. Может расскажешь?

Еденица реальная - это 10000000 псевдоеденицы, которые запмсываются в инт как 10000000. И ты считаешь в псевдоединицах, что тебе тут не ясно?

мне неясно, каким образом ты узнаешь, как вычислять псевдоеденицы нужные в данной операции? И чем это лучше float'а, в котором именно так и считается, и одна «псевдоединица» всегда равна 1/2²³ реальной единицы?

Т.е. ты фактически хочешь свой float замутить? Так? А где ты будешь хранить размер псевдоединицы? float потому и имеет точность 23 бита, из-за того, что ещё 8 бит ушли на размер псевдоединицы, и ещё один бит на знак числа.

Реально? Хорошо? Ты понимаешь, что для чисел с точностью более 7 знаков у твоего float НЕТ реальных представлений чисел.

да, понимаю. Что дальше?

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Я не поделил на ноль - поделил на ноль ты своим детсадовским знанием битиков. Это коммендой я доказал, что представление этих чисел ОДИНАКОГО, а это значит, что сложение разных чисел будет давать ОДИН результат, что противоречит МИРУ. Поэтому ТВОЙ ФЛОАТ И РАБОТАЕТ. ОН ТУПО ОТКИДЫВАЕТ РАЗРЯДЫ.

во первых НЕ тупо. Во вторых, разряды по любому откидывать нужно, ибо их у тебя конечное число. И не важно, сколько именно, 23, 32, 64, или 666.

На ноль ты поделил, не отрицай. Ибо ты не просто откинул разряды, а их УМНОЖИЛ НА НОЛЬ. Но это не страшно. Страшно, когда ты эти разряды ВОССТАНОВИЛ И СРАВНИЛ ИХ ВЕЛИЧИНУ. Т.е. поделил на ноль.

ТАК БУДЕТ ВСЕГДА, ибо ДЛЯ ЧИСЕЛ С КОЛ-ВОМ РАЗРЯДОМ БОЛЬШЕ 7 У ФЛОАТА НЕТ ПРЕДСТАВЛЕНИЯ. ОН ОТКИДЫВАЕТ ЛИШНИЕ РАЗРЯДЫ И ВПИЛИВАЕТ ТУДА МУСОР.

нет. Он туда не мусор впиливает. И не откидывает, а ОКРУГЛЯЕТ.

Твой «int» из псевдоединиц делает тоже самое. В лучшем случае.

Мнение анскильных неосиляторов не интересует.

ты так и не показал своего кода, о суперскильный осилятор.

drBatty ★★
()
Ответ на: комментарий от quasimoto

Точность дабла тут ни при чём — увеличением N получаем улучшение аппроксимации — если ты посмотришь на значения разницы добавляемой к res в for, то увидишь, что она всё меньше по мере роста n, так что N нужно стараться держать как можно бОльшим, но чтобы не получить в итоге nan:

Реально? http://pastebin.com/dZRRt7bV

То есть если ты берешь маленькое N, то просто сильно не добираешь до аналитических значений, так как пропускаешь значимые слагаемые сходящегося ряда.

Я клал на это, клал на аналитические значения - я вижу. что выхлоп после n=40 не меняется - смысла в n нет.

Насчёт bc — оно тут не нужно, есть единственный точный ряд значений (аналитический) который я привёл вторым листингом выше — вот к нему нужно приближаться.

Мне на это без разницы. Твоё деление после n=40 уже будет за точность дабла, а всё, что за точностью дабла - мусор, который нужен для исравления фейлов плавучести при следующей работе с выхлопом.

superhackkiller1997
() автор топика
Ответ на: комментарий от drBatty

Читай коммент выше и не неси ересь. Кто говорил, что после n=40 оно не будет работать? Оно будет работать, но это расчёты за пределами точности дабла и твой выхлоп при n=40 будет равен n=300, а во флоате он загнётся ещё на n10-20.

superhackkiller1997
() автор топика
Ответ на: комментарий от drBatty

Твой начальный бред я разбирать не буду, ибо будет о5 много плохих слов.

мне неясно, каким образом ты узнаешь, как вычислять псевдоеденицы нужные в данной операции? И чем это лучше float'а, в котором именно так и считается, и одна «псевдоединица» всегда равна 1/2²³ реальной единицы?

Наверное вменяемым представлением? Исходя из задачи.

Т.е. ты фактически хочешь свой float замутить? Так? А где ты будешь хранить размер псевдоединицы? float потому и имеет точность 23 бита, из-за того, что ещё 8 бит ушли на размер псевдоединицы, и ещё один бит на знак числа.

В этом и фейл представления. Я знаю свою псевдоеденицу и могу хранить её в другом месте, а не тратить на это место.

да, понимаю. Что дальше?

Это значит, что твой флоат - это просто 7 десятичных разрядов в инте, который откидывает лишние разряды при операциях.

superhackkiller1997
() автор топика
Ответ на: комментарий от drBatty

во первых НЕ тупо. Во вторых, разряды по любому откидывать нужно, ибо их у тебя конечное число. И не важно, сколько именно, 23, 32, 64, или 666.

А как? Сложно?

На ноль ты поделил, не отрицай. Ибо ты не просто откинул разряды, а их УМНОЖИЛ НА НОЛЬ. Но это не страшно. Страшно, когда ты эти разряды ВОССТАНОВИЛ И СРАВНИЛ ИХ ВЕЛИЧИНУ. Т.е. поделил на ноль.

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

Суть мира в том, что не надо умножать что хочешь, а умножение чего-то большечего, чем 7разрядов не имеет смысла.

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

нет. Он туда не мусор впиливает. И не откидывает, а ОКРУГЛЯЕТ.

Это мусор с точки зрения вычисления, но этот мусор помогает флоату округлять правильно - да.

Твой «int» из псевдоединиц делает тоже самое. В лучшем случае.

Да, он даёт тоже самое, только не с таким оверхедом, а множить числа больше, чем 7разрядов не имеет смысла.

Плюс его представление числа более красиво и он показывает сразу, что твои бесконечные значения миф и перестань думать в ЭТОМ МИРЕ своими БЕСПОЛЕЗНЫМИ В ЭТОМ МИРЕ МАТАБСТРАКЦИЯМИ.

ты так и не показал своего кода, о суперскильный осилятор.

Будет у меня часики 3-4 свободного времени - я возьму запилю. Да и причем тут код?

superhackkiller1997
() автор топика
Ответ на: комментарий от PolarFox

Я не говорю, что я что-то изобрёл. Это не совсем фиксед поинт, ибо тут нет самого поинта.

Хотя какбэ и есть - это res/кол-во абстрактных единиц на единицу, но это ненужная абстракция.

superhackkiller1997
() автор топика
Ответ на: комментарий от superhackkiller1997

Оно будет работать, но это расчёты за пределами точности дабла

возьми это: http://en.wikipedia.org/wiki/Extended_precision#x86_Extended_Precision_Format

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

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Будет у меня часики 3-4 свободного времени - я возьму запилю.

Могу помочь. ;)

beastie ★★★★★
()
Ответ на: комментарий от superhackkiller1997

В этом и фейл представления. Я знаю свою псевдоеденицу и могу хранить её в другом месте, а не тратить на это место.

эта псевдоединица меняется В КАЖДОЙ ОПЕРАЦИИ, как ты не можешь этого понять? И CPU её может сам менять и хранить вместе с числом.

А ты предложил хрень непонятную. Задачки для тебя уже были, напиши-ка, где там хранить твою псевдоединицу, и как её выбирать?

Это значит, что твой флоат - это просто 7 десятичных разрядов в инте, который откидывает лишние разряды при операциях.

ну с этим можно согласится. Да, 23 бита это действительно 7..8 десятичных цифр, о чём и речь. А чем ты недоволен?

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Реально?

Посмотри другие значения

N = 40; x = 20; 485152859.445136
N = 70; x = 20; 485165195.40979

Тот же алгоритм (Тейлор экспоненты называется, совсем не так как нужно, но просто чтобы показать что мы считаем):

double f(double x, double dx, int n_max)
{
    double xn = 1., nf = 1., d = 1., res = 0.;
    for (int n = 0; d > dx && n < n_max; ++n, res += d = (xn *= x) / (nf *= n));
    return res;
}

double g(double x, double dx, int n_max)
{
    return x < 0. ? 1 / (f(-x, dx, n_max) + 1.) : f(x, dx, n_max) + 1;
}

можно сделать dx = 0 и выкинуть проверку с n_max, либо как-то их варьировать. Но это не важно — до 10 знаков на нужном интервале для всего разрешения дабла работает? — Да. Дальше вопросы — 1) такты, 2) что там с fixed point?

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Посмотри другие значения

Не интересуют.

можно сделать dx = 0 и выкинуть проверку с n_max, либо как-то их варьировать. Но это не важно — до 10 знаков на нужном интервале для всего разрешения дабла работает? — Да. Дальше вопросы — 1) такты, 2) что там с fixed point?

Нука, как ты такты считал? Т.е. ты считаешь все N, но получешь 20тактов на 100N?

superhackkiller1997
() автор топика
Ответ на: комментарий от drBatty

И за его пределами оно будет. Это не важно, важно лишь то, что теоретически большей N будет давать большу точность, но на практите N больше определённого значения не имеет смысла, ибо уже считает пустоту.

Да, ты прав, такая точность не нужна, но почитай выше - мне доказывали, что нужна.

superhackkiller1997
() автор топика
Ответ на: комментарий от superhackkiller1997

Не интересуют.

Ну то есть значение N может играть роль будучи больше 40, да?

Нука, как ты такты считал?

rdtsc

Т.е. ты считаешь все N, но получешь 20тактов на 100N?

Десятки N — тысячи тактов. «20 тактов» это про другие решения (но тоже на плавающих).

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от drBatty

эта псевдоединица меняется В КАЖДОЙ ОПЕРАЦИИ, как ты не можешь этого понять? И CPU её может сам менять и хранить вместе с числом.

Это нужно для представления числа в флоатформате, не более. Реально ты берёшь 1000000 псевдоединиц и считаешь в них, а если результат деления тебе дал 0 - ты делишь как-то нетак.

А ты предложил хрень непонятную. Задачки для тебя уже были, напиши-ка, где там хранить твою псевдоединицу, и как её выбирать?

В задаче надо пошаманить над степенями - я этого ранее не делал, а пока у меня времени на это нет. А зачем её хранить? У тебя там одно деление и потом 40сложений - это даже без округления можно сделать банальным усечением на 2+разряда.

ну с этим можно согласится. Да, 23 бита это действительно 7..8 десятичных цифр, о чём и речь. А чем ты недоволен?

Про твои задачки. Про счёт бесконечно точных чисел и т.п. Это миф и иллюзия, которая не даёт фейлов из-за устройства флоата.

superhackkiller1997
() автор топика
Ответ на: комментарий от quasimoto

Ну то есть значение N может играть роль будучи больше 40, да?

Ну возьми не 40, а 50 - это не важно. Важно лишь то, что в диапазоне -10 10 N40 хватит, а то, что творится за пределами этого диапазона меня не интересует.

Десятки N — тысячи тактов. «20 тактов» это про другие решения (но тоже на плавающих).

Т.е. это не батл железячный, а просто батл матоптимизаций - ок.

superhackkiller1997
() автор топика
Ответ на: комментарий от superhackkiller1997

А как? Сложно?

тебя в школе не учили округлять? Если первая отбрасываемая цифра == 0, то отбрасываешь, а если 1, то отбрасываешь, и инкрементируешь.

В десятичной замени 0 на 0,1,2,3,4, а 1 замени на 5,6,7,8,9.

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

я и без тебя знал, что точность флоата равна 23 бита. И что?

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

ты определись: мы про бесконечно большие, или про бесконечно точные? Да, бесконечно точное число будет занимать бесконечно много памяти, потому и невозможно. Ну и что дальше-то? Такие и не нужны никому, да и в реальном мире их нет. Один атом железа весит константное число килограмм, а значит, масса железяки равна ЦЕЛОМУ числу. Только псевдоединица очень маленькая, хотя double для неё вполне хватает. Потому массу любой железяки можно ТОЧНО выразить double, если конечно она не очень большая. На танк тебе хватит. С помощью int64 тоже конечно можно, но придётся где-то записать, что это не просто int64, а именно масса железяки. Для double это автоматически хранится.

Это мусор с точки зрения вычисления

нет. Мусор — это то, что правее твоего int'а, которое ты считаешь нулевым. А когда мы(все нормальные люди) считаем числа, то называем это не «мусором», а погрешностью. Погрешность всегда в диапазоне 0..1, величина её неизвестна, но в среднем она равна ½. Вот эту-то половину мы и прибавляем. Потому погрешности не накапливаются. А у тебя — накапливаются, потому-как ты их множишь на ноль.

Да, он даёт тоже самое, только не с таким оверхедом, а множить числа больше, чем 7разрядов не имеет смысла.

а что делать с произведением, в котором 14 разрядов? Оно по твоему тоже «не нужно»? Но ведь, блин, 1234567*7654321==9449772114007

Я не виноват, это калькулятор.

Плюс его представление числа более красиво и он показывает сразу, что твои бесконечные значения миф и перестань думать в ЭТОМ МИРЕ своими БЕСПОЛЕЗНЫМИ В ЭТОМ МИРЕ МАТАБСТРАКЦИЯМИ.

я конечно понимаю, что НЁХ не красивая. Но она СУЩЕСТВУЕТ. И если ты её умножаешь на ноль, то она всё равно вылезет, и тебе отомстит. А вылезет она тогда, когда ты на своё число например поделишь или сравнишь с похожим, или вычтешь похожее. Это называется «потеря точности». Например 100-101==-1, а вот (100/10-101/10)*10==0 в твоих любимых целых числах, хотя в любых float получается правильный ответ.

Да и причем тут код?

при том, что то, что ты говоришь, работать НЕ БУДЕТ.

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Я не говорю, что я что-то изобрёл. Это не совсем фиксед поинт, ибо тут нет самого поинта.

есть. Ты даже название своё придумал: «псевдоединица».

Хотя какбэ и есть - это res/кол-во абстрактных единиц на единицу, но это ненужная абстракция.

хранить её всё равно НУЖНО. Причём по одной на число.

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Это нужно для представления числа в флоатформате, не более. Реально ты берёшь 1000000 псевдоединиц и считаешь в них, а если результат деления тебе дал 0 - ты делишь как-то нетак.

хватит тупить. 1000000*1000000==1000000000000. ЧЯДНТ?

А зачем её хранить? У тебя там одно деление и потом 40сложений - это даже без округления можно сделать банальным усечением на 2+разряда.

одно умножение увеличивает твою псевдоединицу в квадрат. 40 сложений прибавляет к твоей псевдоединице 40 логарифмов 40а псевдоединиц 40а слогаемых. Вычитание соответственно вычитает логарифм. Именно потому псевдоединицу хранят в виде степени числа, что-бы не долбаться с логарифмами(по основному правилу логарифмов, они меняются на сложения).

Про твои задачки. Про счёт бесконечно точных чисел и т.п.

да не гони, никаких там нет «бесконечно точных». Это очень такая востребованная задачка численного решения дифференциального уравнения. В данном случае его можно и аналитически решить, но можно и так, взяв _очень_ малое изменение уровня, и получив достаточную на практике точность, путём не одного, а скажем 100500 вычислений. В древности математики использовали для этого логарифмы, но сегодня любой школьник может их сделать используя компьютер и арифметику в размере начальных классов. Вот только свои int'ы придётся тебе позабыть.

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Т.е. это не батл железячный

тоже железячный, но очевидно используется тот факт, что SSE умеет жрать много float'ов за раз на одном ядре. Потому N float'ов на M ядрах даст в N*M большую скорость. Т.е., если одна итерация у тебя займёт 256 тактов, то у него с N,M==4 всего 16 тактов.

drBatty ★★
()
Ответ на: комментарий от superhackkiller1997

Вот std vs fmath (bench последнего) у меня:

range=[-10.00, 10.00], d=1.000000e-06, N=10
            std::exp sum=2.00411013e+10 ave= 19.5/ 28.5clk(x1.00)
          fmath::exp sum=2.00410952e+10 ave= 11.1/ 20.1clk(x1.76)

range=[-10.00, 10.00], d=1.000000e-06, N=20
            std::exp sum=1.67944243e+10 ave= 19.4/ 28.5clk(x1.00)
          fmath::exp sum=1.67944243e+10 ave= 11.1/ 20.1clk(x1.76)
quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от superhackkiller1997

Т.е. это не батл железячный, а просто батл матоптимизаций - ок.

в основном да, но железо не забыто

вспомни, что в самом начале он тебя просил за раз вычислять не одно значение функции от одного х, а сразу 4 значения от x[4] — это тебе был намек тебе на то, чтобы заюзать sse, но ты не понял, а еще говоришь, что он темнит, гы-гы

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от superhackkiller1997

Да причем тут твоё галимое ссе - это гроши по сравнению с тем, о чем говорит пациент.

бугага

до тебя, кажется, дошло, что твои галимые скиллы железной оптимизации — это гроши по сравнению со скиллами алгоритмической/математической оптимизации?

ну в общем-то да, но когда с помощью ссе есть возможность уменьшить количество тактов с 50 до 25, то это тоже нужно

з.ы. там еще похоже есть один момент в пользу железа, но я его тебе подсказывать не буду

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Ответ на: комментарий от www_linux_org_ru

Нет, дело не в этом. Ты оптимизируешь ненужность для ненужности.

Т.е. посчитать всё это можно изначально проще, но ты считаешь дфу, которые избыточны и потом оптимизируешь их.

superhackkiller1997
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.