Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Вопросы по программированию на C/С++

Автор: Rudia
Дата сообщения: 15.10.2007 12:48
Antananarivu

Цитата:
1. Я так понимаю тип long double сохраняет точность 18 знаков после запятой (поправьте, если не прав).

Это зависит от компилятора, я пользуюсь vs2005 - там он эквивалентен обычному double - следовательно имеет точность 15 знаков после запятой.

Цитата:
2. Есть какая-то функция:

Код:
int F(int &v1);

Я сейчас этой функции передаю не ссылочный параметр &v1, а сам v1 (ну то есть вызываю так - F(v1) ), вроде бы все работает. А чем такие вещи вообще чреваты?

Применение адресного оператора к ссылочному типу дает такой же результат, как применение этого оператора к объекту, на который указывает ссылка.
то есть
int i;
int& j = i;
будет
&j == &i
Автор: Antananarivu
Дата сообщения: 15.10.2007 12:55
2. То есть иными словами, я функцию int F(int &v1) могу вызвать как

Код: int v1;
F(v1),
Автор: RedLord
Дата сообщения: 15.10.2007 13:07
Mr Nobody

Цитата:
Как мне смутно вспоминается, по стандарту new не взвращает теперь при сбое NULL, а нужно использовать bad_alloc.


C++ 14882 (5.3.4)


Цитата:

[Note: unless an allocation function is declared with an empty exception-specification (15.4), throw(), it
indicates failure to allocate storage by throwing a bad_alloc exception (clause 15, 18.4.2.1); it returns a
non-null pointer otherwise. If the allocation function is declared with an empty exception-specification,
throw(), it returns null to indicate failure to allocate storage and a non-null pointer otherwise. ]

Автор: Mr Nobody
Дата сообщения: 15.10.2007 14:09
RedLord
Как я вспоминаю, лень уточнять, можно и так и так. Понятно! Спасибо.
Автор: floodway
Дата сообщения: 15.10.2007 14:15
Antananarivu

Цитата:
И это будет верно?

На долю секунды представьте, что v2 - это алиас, синоним, для вашей v1, тогда вы может немного проникнитесь идеей.
Автор: Mr Nobody
Дата сообщения: 15.10.2007 14:19
Antananarivu

Цитата:
1. Я так понимаю тип long double сохраняет точность 18 знаков после запятой (поправьте, если не прав). Так вот допустим у меня такая ситуация:

Тип long double или 80 бит, это внутренне представдение данных в математическом процессоре. Все результат сопроцессор просчитывает с точностью 80 бит, для повышения точности расчета, потом округляет их к внешнему представлению 32 и 62 бита. Честно скажу вам, я не представляю, когда надо использовать long double для внешнего представления и не помню, что бы кто то это использовал в прграммировании.
Пользуйтесь double и не делайте себе проблемы.
Автор: Antananarivu
Дата сообщения: 15.10.2007 14:39
Ок - у меня все переменные типа double, перемножается значительный массив чисел. В итоге ошибка почти всегда проскакивает в 15 знаке, очень редко в 14. Это нормально? Или ошибка в 14 знаке автоматически говорит о том, что я где-то "теряю точность".
Автор: WiseAlex
Дата сообщения: 15.10.2007 14:46
Antananarivu
1) числа с десятичной запятой не всегда можно точно представить на компьютере
2) точность не 15 знаков после запятой, а всего 15 знаков, поэтому если в процессе вычислений целая часть будет иметь 3 знака, то и число знаков после запятой снизится
3) для очень точных расчетов обычно используют специализированные библиотеки
Автор: Antananarivu
Дата сообщения: 15.10.2007 15:20
WiseAlex
Спасибо, теперь все стало ясно.
Автор: Mr Nobody
Дата сообщения: 15.10.2007 19:27
Antananarivu, что у вас за вычисления, что 14 значащих цифр вам мало? Как я понимаю, вы не математик - вычислитель и не можете делать что либо грандиозное в этой области. Может вам и 32 бит хватит?


Цитата:
3) для очень точных расчетов обычно используют специализированные библиотеки

И язык Фортран. Это его область!
Автор: Antananarivu
Дата сообщения: 15.10.2007 20:17
Mr Nobody
Ха... А вот сейчас будет страшно. Я, конечно, слабый математик, к сожалению, но математик. И сейчас в ЦУПе идет переделывание (хотя слово идет - довольно оптимистичное, точнее я пытаюсь что-то сделать) огромного комплекса по прогнозированию движения КА и КО с Фортрана-77 на С++ (новое поколение не хочет вязаться с Фотраном, хотя я согласен, что он создан специально для вычислений в общем-то). Так что в Ваших интересах мне помогать по мере сил, а то скоро падать все начнет...
Автор: Mr Nobody
Дата сообщения: 15.10.2007 20:47
Antananarivu
Как я понял ЦУП - это Центр Управления Полетами? А что такое КА и КО?
Как мне показывал мой опыт программирования на С++ классы безполезны при численном прграммировании. То есть С++ сведется к С. Что это даст, да ничего, кроме дополнительных, трудно уловимых ошибок.
Мой вам совет, идите на соседнию ветку Фортрана, я уверен, там есть кто встречался с портированием Фортрана на С и С++. Может я и ошибаюсь, это будет хорошо.
Автор: Antananarivu
Дата сообщения: 15.10.2007 20:57
Mr Nobody
КА - космический аппарат. КО - космический объект. КА - рукотворные аппараты, КО - любой космический объект.
Да поздно уже. Во первых, я сам довольно плохо знаю Фортран. Во-вторых, я не начальник и мне дали такое задание. Третье, огромная часть комплекса уже написана ( не знаю, классы прекрасно работают - пока точности хватало, посмотрим что будет дальше - например интегратор описан как класс) и я его дорабатываю - сейчас в частности занимаюсь кодированием краевой задачи методом наименьших квадратов.
Автор: Mr Nobody
Дата сообщения: 15.10.2007 21:55
Antananarivu

Цитата:
Во первых, я сам довольно плохо знаю Фортран

Для изучения Фортрана 77 человеку, который разобрался в Пискунове, достаточно тоько два месяца. Причем с нуля. С++, как мне кажется, занял у меня больше двух лет, и то я не уверен, быстрей всего больше.

Цитата:
не знаю, классы прекрасно работают - пока точности хватало, посмотрим что будет дальше - например интегратор описан как класс

Вы меня извините, то вы знаете, что такое в С++ класс. Если можно, то я бы хотел посмотреть на класс, который осуществляет численное интегрировние?
Что мне еще не понятно, так если работает, то зачем трогать?


Автор: Antananarivu
Дата сообщения: 15.10.2007 22:31
Mr Nobody
Я всего не знаю. Насколько я знаю, все это дело берет информанцию из базы данных Oracle. Работа с Ораклом организована методоми Java. Также весь интерфейс Java. А уже из Java вызываются С++ методы. Насколько я знаю Java и C++ очень хорошо друг с другом взаимодействуют. Я не знаю возможно ли это сделать средствами Fortrana (взаимодействие с Java - развитый интерфейс, возможно?), а если даже да, то видимо программист, реализующий это дело либо об этом не знал, либо имел какие-то свои причины для перевода все на С++, о которых я и не догадываюсь.
Возможно использование именно Java и С++ - обязательство перед заказчками по ТЗ, кем-то когда-то подписанному.
Класс интегратор. Ну даже я, в общем-то пока ламер С++, вижу что все это сделано не блестяще - никакого ООП в сущности не наблюдается, так процедурное программирование.
Вы вообще должны понимать, что средний возраст работников моего отдела 60 лет, многие остановились на Алголе, многие ушли, а я занимаюсь С++ около 3 месяцев и то - постольку-поскольку. Что имею - то и имею.
P.S.
Бонус:

Код: class CIntegrator //public Satellite
{
public: //methods

    CIntegrator(long jt0,LDouble tj0,T3DVector* rv,Perturbation_set* right,short power=13,LDouble eps =1.E-15);
    virtual ~CIntegrator();
    virtual void GetVector(LDouble tj,T3DVector* rv);
    virtual void GetMatrix(NMTMatrix &matrix);
protected:// methods
    virtual void Fsp(T3DVector* f, LDouble *B, T3DVector* sum);
    T3DVector Sum(T3DVector* fun,LDouble h_tau);
    void SumRV(LDouble h_tau, T3DVector *f1, T3DVector *f2);
public:// members
    long        m_countStep;//step' counter
    long        m_countForce;//forc' counter
protected:// members
    long m_p_JT0;
    LDouble m_p_T0;
    T3DVector* m_p_RV0;
    short m_nPower;
    LDouble        m_Tau[15];
    LDouble        m_cTau[15];
    LDouble        m_B1[225];//[15*15] 1st order integrator matrix
    LDouble        m_B2[225];//[15*15]2nd order integrator matrix
    LDouble        m_eps;    // Integerator error
    LDouble        m_h;    // Current step
    LDouble        m_tCur;//Current time
    LDouble        m_hCorrector;//corrector's step
//    LDouble        m_h_min;// min step
//    LDouble        m_h_max;//max step
    short        m_nMiddle;// center of sequence
    short        m_direction;// direction of integration +1 time forward -1 time backward
    short        m_nBegin;//depend from direction
    short        m_nFinish;//depend from direction
    short        m_nNextStep;// depend from direction
    T3DVector    m_rvOld[15][2];//velocities in history of integration
    T3DVector    m_fOld[15];//accelerations in history of integration
    T3DVector    m_rvStep[15][2];//current step series velocities
    T3DVector    m_fStep[15];//current step series accelerations
    short        m_nCalc[15];//check every point by eps
    short        m_bInitFlag;//first step flag
    short        m_Flag;
    Perturbation_set* m_pRight;
    LDouble m_PM[15];
};
Автор: Mr Nobody
Дата сообщения: 16.10.2007 08:33
Antananarivu, это какой то класс, совмещенный с MFC. У поклонников этой библотеке всегда появляется привычка писат с "бородавкой" m_, сам прошел через это.
Мой совет, обратитесь на ветку Фортрана, вам больше помогут, чем на этой ветке.
Это моё мнение.
Автор: WiseAlex
Дата сообщения: 16.10.2007 10:36
Antananarivu
действительно для меня загадочен переход на с++. Есть ощущение, что просто модно. Отсутствие специалистов так же не аргумент - фортран не слишком сложен.
Думаю, что совместить java и fortran вполне возможно. Да и с++ и фортран не сложно.
на с++ тяжело делать оптимизацию вычислений - бесконечная борьба с ненужными временными объектами (для собственных численных классов)...
Для фортрана есть хорошо оптимизированные библиотеки (во всяком случае для x86 платформы- от интел например)
Кстати вы пишите только под x86 или еще для чего-то? Если еще под что-то, то тогда с++ может быть предпочтительнее
Mr Nobody

Цитата:
m_

модные тенденции - подчеркивание в конце или начале, с другой стороны когда набираешь m_ всегда подсказка точная, поэтому я до сих пор использую m_ и в не mfc проектах.
Автор: Antananarivu
Дата сообщения: 16.10.2007 10:52
Да, P4 везде стоят. На сервере (где база данных) Unix, на клиентских - XP. Не знаю я, видимо погнались за модой, красотой и интерфейсом. А совмещать джаву с фортраном, думаю, банально никто и не умеет. Я сегодня спрошу - отпишусь, что мне ответят.
Автор: Sacramento
Дата сообщения: 16.10.2007 11:25
Пожалуйста, помогите чайнику

Пытаюсь написать DLL на C++ естественно, а затем вызвать экспортируемую функцию скажем на C#(последнее роли не играет, но тестирую именно на нем)

Нужно сделать так, чтобы возврат значений происходит через параметры функции. Например: (естественно я объявил эту функцию как экспортируемую в DEF-файле)

--------С++-------
DWORD GetDrive(BYTE ucIndex, TEST sDrive)
{
ucIndex=44; //присваивание переменной ucIndex значения
//никак не отображается в вызываемой функции
sDrive.Info=3//как собственно и попытка изменить параметры структуры
...
return(22); //обычный возврат проходит успешно
}
---------------------

пытаюсь вызывать эту функцию вот так
---------С#--------
[DllImport("DriveRead.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
static extern int GetDrive(ref byte ucIndex, ref TEST sDrive);

void Test()
{
TEST di= new TEST(); //Создаю структуру TEST
int gg = 0;
byte dd = 0;
gg = GetDriveInfo(ref dd, ref di); //Вызываю функцию
//Результат
//gg=22 - все в порядке
//dd=0 -
//di - также не изменился
}

В C# возврат значений через параметры функции плювое дело, а как это сделать в C++? Причем для экспортируемых функций.
Перебрал около 20 книжек по C++, но решения не нашел (поисковики, что-то молчат, а может я искать не умею)
Автор: Mr Nobody
Дата сообщения: 16.10.2007 11:35
Sacramento, как мне кажется на первый взглят, ты пишеш DLL не на C++, а на С. Когда ты пишеш на С++ линкер добавляет всякие "украения" к имени функции. Если вы напишете extern C, то имя функции останется неизменным. Как я помню, что DLL на C++ идут в рамках одного компилятора.
Автор: Rudia
Дата сообщения: 16.10.2007 11:37
Sacramento
Вообще то в качестве параметров функций, реализованных в DLL не рекомендуется использовать пользовательские типы данных. Так как каждый язык, даже различные компиляторы используют свою модель памяти. А параметры, типа класс передаются по ссылке. То есть функция в библиотеке получает ссылку на область памяти где расположен класс, но из-за другого менеджера памяти она может считать вообще левую информацию. Так что пример, описанный выше возможно заработает, только если программа и библиотека будут написаны на одном языке и собраны одним компилятором. Так что используйте в качестве параметров простые порядковые типа данных, массивы символов и будет вам счастье).
Автор: distance
Дата сообщения: 16.10.2007 12:09
Rudia

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

Ничего подобного. Касаемо C#, он позволяет свободно обмениваться пользовательскими типами данных, равно как и интерфейсами, областями памяти etc

Sacramento
на первый взгляд, у тебя неправильно передаются параметры - по ЗНАЧЕНИЮ, а стало быть, в функции изменяются всего лишь копии.

DWORD GetDrive(BYTE* ucIndex, TEST* sDrive) - начни отсюда.
Автор: Sacramento
Дата сообщения: 16.10.2007 12:12

Цитата:
как мне кажется на первый взглят, ты пишеш DLL не на C++, а на С. Когда ты пишеш на С++ линкер добавляет всякие "украения" к имени функции. Если вы напишете extern C, то имя функции останется неизменным. Как я помню, что DLL на C++ идут в рамках одного компилятора.

Нет, я пишу на Visual C++ 2005. Насчет украения, тут все в порядке, имена функций остаются такими, какими я их назвал, так как я их принудительно задаю в DEF файле. Да и вызывается эта функция без проблем, просто не хочет возвращать значения через параметры.

Цитата:
Вообще то в качестве параметров функций, реализованных в DLL не рекомендуется использовать пользовательские типы данных. Так как каждый язык, даже различные компиляторы используют свою модель памяти. А параметры, типа класс передаются по ссылке. То есть функция в библиотеке получает ссылку на область памяти где расположен класс, но из-за другого менеджера памяти она может считать вообще левую информацию.

Согласен, но дело даже не в типах данных. Я использовал BYTE и структуру только для примера. Дело в том, что у меня не получается возврат через параметры ни с одним типом данных, буть то байт или integer. API-е функции от майкрософта (в DLL типа kernel32, gdi и пр.) Проделывают такие вещи без проблем с любым типом данных, только вот как?

Я предполагал, что надо использовать в параметрах конструкции типа "[out] int var", но что-то все равно не получается.



Добавлено:

Цитата:
DWORD GetDrive(BYTE* ucIndex, TEST* sDrive) - начни отсюда.

Попробовал
----
DWORD GetDrive(BYTE *ucIndex, TEST *sDrive)
{
*ucIndex=44;
sDrive->Info=3;
...
return(22);
}

и получил (в настройках проекта C# я пометил, что код unsafe)
----
The runtime has encountered a fatal error. The address of the error was at 0x79f1c184, on thread 0x7ec. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
----

хотя, без указателей и функция вызывалась и число 22 возвращалось

Если можно, напишите рабочий пример.
Автор: Rudia
Дата сообщения: 16.10.2007 12:26

Цитата:
Ничего подобного. Касаемо C#, он позволяет свободно обмениваться пользовательскими типами данных, равно как и интерфейсами, областями памяти etc

dll вообще то чаще всего используются когда надо предоставить некоторые функции, которые должны работать и при вызове из другого языка программирования, использование в качестве параметров классов сводит это преимущество на нет. У меня на работе система есть, написанная на 4 дельфи, она использует dll-ки в качестве расширений, так вот из-за того, что туда передаются классы, система будет некорректно работать с ними, если их скомпилировать даже в более поздней версии делфи, не говоря уже о других языках. Приходится сидеть на 4
Автор: Antananarivu
Дата сообщения: 16.10.2007 12:44
WiseAlex Mr Nobody
Причины, по которым Фортрановский комплекс стал в середине 80-ых - начале 90-ых переводится на рельсы С С++ и Java.
1). Неудобство реализации самого комплекса. Многие вещи были в свое время запрограммированы не лучшим образом. В итоге для добавления или изъятия, скажем, одной из возмущающих сил приходилось лезть в процедуру и менять десятки строк, что тянуло за собой как снежный ком другие процедуры.
2). Комплекс на С++ упрощенная и сильно переработанная фортрановская версия.
3). В середине 80 -начале 90 - был большой упадок сил, скажем так. Фортран был в некотором запустении, как мне сказали, не было ни графических каких-то возможностей, не было такой хорошей согласованности с С и Java.
4). Java гораздо более машинно и системно независимый язык, чем тот же Fortran 77, у нас есть и Unixовые машины и Windowсовые. Fotran по крайней мере 77, по разному реагировал на такие вещи, что было неудобно - приходилось его дорабатывать.
5). Неопытному программисту и оператору работать с классами С++ значительно удобнее, если надо что-то поменять быстро в программе особо не вникая в ее суть (суть интегратора, алгоритма и т.д.) Вникать и переделывать процедуры Fortran где зачастую, чтобы что- то изменить, нужно поменять сотни строк в десятке файлов, гораздо сложнее, чем в С++.
6). "Ты не думай - это не прихоть какая-то и не блажь."
Вот такие причины мне озвучили. Согласитесь Вы с ними или признаете их необоснованность - не знаю. Но для меня обратной дороги уже нет.
Автор: Sacramento
Дата сообщения: 16.10.2007 12:50

Цитата:
DWORD GetDrive(BYTE* ucIndex, TEST* sDrive) - начни отсюда.

После недолгих испытаний, выяснилось что передача параметров используя указатели работает без проблем только для byte, int и пр. стандартных типах данных (хоть что-то!!!), а ошибка о которой я писал выше вылазит если я пытаюсь использовать структуру.
Т.е.
это работает - DWORD GetDriveInfo(BYTE *ucDriveIndex)

А вот это - DWORD GetDriveInfo(BYTE *ucDriveIndex, TEST *sDriveInfos)
нет. Если быть точным, то ошибка вылазит тогда, когда я пытаюсь изменить значение одного из параметров структуры (которая была создана в C# и передана через указатель)

Может я ее не правильно объявляю:

В С++ я пишу так:
---
typedef struct
{    
    int Info;
    int Other;    
}TEST;
---

И вот так в C#
---
public struct TEST
{
public int Info;
public int Other;
}

В чем подвох? То, что со стандартными типами получается это гуд, но я планирую по большей части использовать структуры, так как массивы быйтов слишком сложно да и не юзабельно.
Автор: distance
Дата сообщения: 16.10.2007 13:04
Sacramento
что-то у тебя значит неправильно...
повторил твой тест:

код на C++ (чуть подправлен результат генерации визарда)
Код: // в *.h

struct TEST
{
    int Info;
};

typedef TEST* LPTEST;

extern "C" CS_DLL_API int GetDrive(LPBYTE lpIndex, LPTEST lpDrive);

// в *.cpp
CS_DLL_API int GetDrive(LPBYTE lpIndex, LPTEST lpDrive)
{
    *lpIndex = 44;
    lpDrive->Info = 22;
    return 42;
}
Автор: Rudia
Дата сообщения: 16.10.2007 13:10

Цитата:
В чем подвох?

Подвох в менеджере памяти, как я писал выше, структура = класс.
Объясняю грубо на пальцах, ибо самому не хочется лезть в дебри:
пусть в С++ класс представлен в памяти как [служебная информация (n байт)][область хранения элементов (n1 байт)]
в С# [служебная информация (m байт)][область хранения элементов (m1 байт)]
Так вот в С++ и C# эти области могут иметь совершенно разную структуру, а вы в качестве параметров передаете просто указатель на начало этой области памяти и C++ интерпретирует её по-своему, а C# - по своему.
Так что функции в dll на С++ скорее всего портит структуру класса С# - поэтому и фатальные ошибки лезут.
Автор: distance
Дата сообщения: 16.10.2007 13:19
Rudia

Цитата:
Подвох в менеджере памяти, как я писал выше, структура = класс.

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



Цитата:
When platform invoke calls an unmanaged function, it performs the following sequence of actions:
1. Locates the DLL containing the function.
2. Loads the DLL into memory.
3. Locates the address of the function in memory and pushes its arguments onto the stack, marshaling data as required.
Note Locating and loading the DLL, and locating the address of the function in memory occur only on the first call to the function.
4. Transfers control to the unmanaged function.
Автор: WiseAlex
Дата сообщения: 16.10.2007 13:49
Antananarivu
сейчас скажу крамольную мысль: по сравнению с началом 90х производительность выросла на порядок - может не стоит мучиться и написать все вычисления на java?

Страницы: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193

Предыдущая тема: не знаю как назвать тему :-)


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.