К примеру у меня есть какой-то объект типа Object многопоточное чтение которого происходит
гораздо чаще, чем модификация и есть два варианта реализации:
a) обычная переменная Object obj и ReadWriteLock соответственно на методы чтения
и модификации
б) volatile Object obj, на метод модификации - простой Lock, создание нового объекта
и замены ссылки obj. Метод чтения без синхронизации(не считая записи-чтения volatile
переменной)
Какой из вариантов предпочтительнее и будет работать быстрее и почему?
Если я решил делать вариант 1.б и точно знаю, что мое приложение будет запускаться
на сервере с несколькими процессорами архитектуры x86-64, то мог ли я вообще убрать
volatile и нарушив тем самым JMM, но полагаясь на протоколы когерентности кешей процессоров?
прочитает ли ядро 2-го процессора измененные данные в ядре первого и даст ли это хоть
какой-то прирост производительности?
Ответы
Ответ 1 Интересный вопрос. Попробую ответить, хотя не претендую на правильность. Буду рад
замечанием в комментариях.
1) Какой вариант будет быстрее? Сказать трудно, потому что все сильно зависит от
usecas'а который вы используете. А именно, от количества писателей и читателей, частоты
записи и чтения, потребность в "честной" синхронизации или ее критичности и пр. В
общем, нужно замерять и писать тесты. Написал для этого вот такой код :
Для варианта с Lock:
private Object object = new Object();
private final ReentrantLock lock = new ReentrantLock();
Supplier reader = () -> {
while (lock.isLocked()) {
}
return object;
};
Function writer = number -> {
lock.lock();
object = number;
lock.unlock();
return object;
};
Насколько я знаю, isLocked() и unlock() имеют отношение happens-before и надобности
в volatile для поля object нет.
Варианта с ReentrantReadWriteLock довольно простой:
private Object object = new Object();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
Supplier reader = () -> {
Object result;
readWriteLock.readLock().lock();
result = object;
readWriteLock.readLock().unlock();
return result;
};
Function writer = number -> {
readWriteLock.writeLock().lock();
object = number;
readWriteLock.writeLock().unlock();
return object;
};
Результаты получились следующие, если отношение между читателями и писателями 0.8
то вариант с обычным lock оказывается быстрее в 2.5-4 раза (полный код теста с jmh)
2) Из полученных измерений пришел к выводу, что удаление volatile не сыграет существенной
роли. Лучше посмотреть в сторону каких-то альтернативных механизмов синхронизации.
#php #phpstorm
Хочу подключить папку к проекту и работать в ней но она лежит вне папки проекта,
как это можно сделать?
Ответы
Ответ 1 Откройте настройки (ctrl + alt + s), зайдите в раздел Directories и справа добавьте
новый content root:
После этого в дереве каталогов проекта появится новая папка.
Ответ 2 Заходим с Settings->Directories. Там будет +Add Content Root. Добавляем папку и наслаждаемся.
#mysql #sql
Имеется таблица
id|cat_id|name
1| 1|test1
2| 1|test2
3| 2|test3
4| 3|test4
5| 3|test5
6| 1|test6
Нужно сделать выборку так, чтобы в ней было не более чем 2х товаров из каждой категории.
Как это сделать?
Вот ссылка на БД, для проверки
https://dl.dropboxusercontent.com/u/8025044/table.sql
Ответы
Ответ 1 Думаю проще всего это будет сделать с использованием переменных:
select *
from (
select T.*,@n:=if(@cat=cat_id,@n+1,1) as Num,@cat:=cat_id
from test7 T,(select @n:=0,@cat:=0) A
order by cat_id
) A
where Num<=2
Сортировка во внутреннем подзапросе должна обязательно начинаться с cat_id, далее
к ней можно добавлять другие поля, что бы регулировать какие именно из двух записей
показывать.
Вариант "обычным SQL":
select *
from test7
where id in(select max(id) from test7 group by cat_id
union
select min(id) from test7 group by cat_id
)
Из ограничений метода: из любой группы всегда выбирается запись с минимальным и максимальным ID.
#cpp #cpp11
Рассмотрим следующий псевдокод:
класс Параметр {
double значение_;
public:
Параметр& задать(const double& зн){ значение_=зн; return *this; }
Параметр& задать(double && зн){ значение_=зн; return *this; }
};
но вернее будет общий случай:
template
класс Параметр {
T значение_;
public:
Параметр& задать(const T& зн){ значение_=зн; return *this; }
Параметр& задать(T && зн) { значение_=зн; return *this; }
};
В чём может быть профит от использования здесь rvalue? Я понимаю, что так как в любом
случае идёт копирование в rvalue нет никакого смысла.
Покажите, пожалуйста, на примере близком к этому когда же может получится польза.
На (2) пример бы написал такой(благодарю ixSci)
класс Параметр {
std::string значение_;
public:
Параметр& задать(const std::string & зн){ значение_=зн; return *this; }
Параметр& задать(std::string && зн) { значение_=std::move(зн); return *this; }
};
Получается на сложных объектах это может сэкономить производительность.
Ответы
Ответ 1 В первом куске кода ссылки не нужны вообще, так что в обоих примерах их нужно убрать
— там лучше обычное копирование, т.к. double. Второй пример — другое дело. Давайте
рассмотрим возможные варианты вызова функции задать:
задать("тему"). Для такого вызова сначала будет создан временный объект типа std::string,
затем, для варианта с const&, будет вызван оператор присваивания, который выделит память,
скопирует строку, а потом будет вызван деструктор временного объекта, который удалит
временный объект и память, которую он выделял на куче(в случае оптимизации малых строк,
никакой памяти не будет, но это оставим за скобками).
Во втором варианте никакого копирования не произойдёт, вернее произойдёт копирование
указателя, из временного объекта в постоянный.Что гораздо быстрее, чем копирование
всей строки(с предварительным выделением памяти), после чего будет так же вызван деструктор
временного объекта, который ничего уже не будет делать.
Все плюсы перемещающей семантики зависят исключительно от того, как реализован перемещающий
конструктор(оператор присваивания). В std::string он реализован так, чтобы он имел
преимущества перед копированием. К этому должен стремиться любой класс содержащий ресурсы.
В стандартной библиотеке этим преимуществом пользуется все классы, которые могут.
Ответ 2 rvalue-ссылка интресена только для объектов, чей класс предусматривает оптимизорованный
продуманный специальный конструктор перемещения. Хорошая STL - хороший пример.
На простых типах от неё толку как от обычной ссылки - может сэкономить копирование
нескольких маш.слов = sizeof(type)-sizeof(void*). То есть при копировании большого
массива double на 32-битной машине даст 2ую экономию.
подходит.
Благодарю @ixSci. Я перефразировал до краткости по сути вопроса.
#cpp #dll #directx #hook
Здравствуйте! Пытаюсь сделать меню для игрушки, но не могу разобраться в функции,
которая крашит программу после инъекции. Опишу все подробно с комментариями, если я
не прав, пожалуйста поправьте:
Создаю поток в процессе (инжект работает нормально) с таким содержимым:
DWORD*vtbl = 0;
//Здесь я записываю начальный адрес модуля
DWORD hD3D9 = (DWORD)LoadLibraryA("d3d9.dll");
//ищу функцию Direct3DCreate или что то другое?
DWORD table = MemHack->FindPattern(hD3D9, 0x128000, (PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86",
"xx????xx????xx");//
// со смещением в 2 байта копируем указатель
memcpy(&vtbl, (void*)(table + 2), 4);
Здесь table = 6ace76d3. Вот кусок памяти:
d3d9.Direct3DCreate9Ex+54AC - E8 71000000 - call d3d9.Direct3DCreate9Ex+5522
d3d9.Direct3DCreate9Ex+54B1 - 33 C0 - xor eax,eax
d3d9.Direct3DCreate9Ex+54B3 - C7 06 9C86CD6A - mov [esi],d3d9.dll+869C { [6ACD9D30] }
d3d9.Direct3DCreate9Ex+54B9 - 89 86 08310000 - mov [esi+00003108],eax
d3d9.Direct3DCreate9Ex+54BF - 89 86 00310000 - mov [esi+00003100],eax
Далее идет вызов функции, который крашит программу:
// vtbl[42] указывает на функцию endScene размером 5 байт?
pEndScene = (oEndScene)Mem->Create_Hook((PBYTE)vtbl[42], (PBYTE)myEndScene, 5);
Приведу код функции, который в общем представлении я не понял:
void * cMemory::Create_Hook(BYTE *src, const BYTE *dst, const int len)
{
BYTE *jmp;
DWORD dwback;
DWORD jumpto, newjump;
VirtualProtect(src,len,PAGE_EXECUTE_READWRITE,&dwback);
// вот отсюда я не понял зачем эта проверка вообще нужна
if(src[0] == 0xE9)
{
jmp = (BYTE*)malloc(10);
jumpto = (*(DWORD*)(src+1))+((DWORD)src)+5;
newjump = (jumpto-(DWORD)(jmp+5));
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = newjump;
jmp += 5;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src-jmp);
}
else
{
jmp = (BYTE*)malloc(5+len);
memcpy(jmp,src,len);
jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src+len-jmp)-5;
}
src[0] = 0xE9;
*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
for(int i = 5; i < len; i++)
src[i] = 0x90;
VirtualProtect(src,len,dwback,&dwback);
// здесь указатель на функцию?
return (jmp-len);
}
Ответы
Ответ 1 Ваши ошибки:
Игра написана на directX8, а не 9 версии, Вы пытаетесь хукнуть 9 версию, собственно
LoadLibraryA("d3d9.dll"), нужно LoadLibraryA("d3d8.dll") и в таблице виртуальные методы
там, на сколько я помню, имеют немного другую последовательность (для проверки того,
какую версию dx использует приложения нужно всего лишь открыть отладчик и просмотреть
список загруженных модулей или посмотреть инфо в википедии).
Вы пытаетесь(скорее всего, это мои догадки) сделать иньекцию кода в процесс generals.exe,
но это просто дочернее окно и оно не выполняет функции отрисовки игрового мира\меню
и т.д., Вам нужен процесс game.dat.
Вечером, когда приду домой, постараюсь переделать Ваш код в рабочее состояние и дополню
ответ. Если Вам интересно, можете почитать интересную статью по Вашей теме.
UPD:
#include
#include
#include
#pragma comment (lib, "d3d8.lib")
#pragma comment (lib, "d3dx8.lib")
#pragma comment( lib, "LIBCI.lib" )
#include "MessageControll.h"
#include "ConsoleControll.h"
//"Game.dat"+0056C9A4
// Hook Function
HRESULT WINAPI HookedPresent(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect,
CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
HRESULT WINAPI HookedReset(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *params);
// Orig Function
typedef HRESULT(WINAPI* tPresent)(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect,
CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
typedef HRESULT(WINAPI *tReset)(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *pp);
DWORD origReset = 0, origPresent = 0;
tPresent _tPresent = nullptr;
tReset _tReset = nullptr;
ID3DXFont* pFont = nullptr;
void createFont(IDirect3DDevice8* pDevice)
{
LOGFONT log_font = {
50, //height
0, //width;
0, // lfEscapement;
0, //lfOrientation;
FW_BOLD, // lfWeight;
FALSE, // lfItalic;
FALSE, // lfUnderline;
FALSE, // lfStrikeOut;
DEFAULT_CHARSET, // lfCharSet;
OUT_DEFAULT_PRECIS, //lfOutPrecision;
CLIP_DEFAULT_PRECIS, // lfClipPrecision;
ANTIALIASED_QUALITY,// lfQuality;
DEFAULT_PITCH,// lfPitchAndFamily;
"Tahoma"// lfFaceName[LF_FACESIZE];
};
HFONT font = CreateFont(10, 10, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET,
OUT_OUTLINE_PRECIS, 0, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
if (D3DXCreateFontIndirect(pDevice, &log_font, &pFont) != D3D_OK)
{
console("D3DXCreateFontIndirect error!");
}
}
VOID D3DX_Font(LPDIRECT3DDEVICE8 Device_Interface)
{
RECT Rect = { 0,0,1000,1000 };
//if (Device_Interface != NULL)
//{
// HFONT Logical_Font_Characteristics = CreateFont(16, 0, 0, 0, 400, 0, 0, 0,
0, 0, 0, 2, 0, "Arial");
// if (Logical_Font_Characteristics != NULL)
// {
// D3DXCreateFont(Device_Interface, Logical_Font_Characteristics, &pFont);
// DeleteObject(Logical_Font_Characteristics);
// }
//}
if (pFont != NULL)
{
pFont->Begin();
pFont->DrawText("StackOverflow.ru!", -1, &Rect, 0, 0xFFFF0000);
pFont->End();
}
}
//=========================================================
//if (bDrawText && m_pFont)
//{
// PrintTextB(m_pFont,
// 250, 20, //x, y
// 255, 255, 255, 255, //color values (and then alpha)
// "Testing 1234567890!!!");
//}
//My custom PrintText Function:
//void drawText(const D3DXVECTOR4& area, const DWORD& color, TCHAR *text, ...)
//{
// TCHAR buf[1024]{};
//
// RECT FontRect = {
//
// (long)area.x,
// (long)area.y,
// (long)area.x + (long)area.z,
// (long)area.y + (long)area.w
// };
//
// va_list vaList;
// va_start(vaList, text);
//
//#ifdef UNICODE
// vswprintf_s(buf, text, vaList);
//#else
// vsprintf_s(buf, text, vaList);
//#endif
//
// va_end(vaList);
//
// pFont->Begin();
// pFont->DrawText(buf, -1, &FontRect, 0, color);
// pFont->End();
//}
void* DetourCreate(BYTE *src, const BYTE *dst, const int len)
{
BYTE *jmp;
DWORD dwback, dwold;
DWORD jumpto, newjump;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &dwback);
if (src[0] == 0xE9)
{
jmp = (PBYTE)malloc(10);
VirtualProtect(jmp, 10, PAGE_EXECUTE_READWRITE, &dwold);
jumpto = (*(DWORD*)(src + 1)) + ((DWORD)src) + 5;
newjump = (jumpto - (DWORD)(jmp + 5));
jmp[0] = 0xE9;
*(DWORD*)(jmp + 1) = newjump;
jmp += 5;
jmp[0] = 0xE9;
*(DWORD*)(jmp + 1) = (DWORD)(src - jmp);
}
else
{
jmp = (PBYTE)malloc(5 + len);
VirtualProtect(jmp, 5 + len, PAGE_EXECUTE_READWRITE, &dwold);
memcpy(jmp, src, len);
jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp + 1) = (DWORD)(src + len - jmp) - 5;
}
src[0] = 0xE9;
*(DWORD*)(src + 1) = (DWORD)(dst - src) - 5;
for (int i = 5; i < len; i++)
{
src[i] = 0x90;
}
VirtualProtect(src, len, dwback, &dwback);
return (jmp - len);
}
void GetDevice9Methods()
{
D3DDISPLAYMODE ds{};
D3DPRESENT_PARAMETERS pp{};
IDirect3DDevice8* dev{};
HMODULE hD3D8Dll = GetModuleHandle("d3d8.dll");
//console("address \"d3d8.dll\" [%#x]", hD3D8Dll);
//Инициализируем свой девайс, чтобы узнать адреса функций ресета и презента в
виртуальной таблице методов
if (hD3D8Dll)
{
IDirect3D8* d3d8 = Direct3DCreate8(D3D_SDK_VERSION);
//console("address \"IDirect3D8\" [%#x]", d3d8);
if (d3d8->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ds) != D3D_OK)
{
d3d8->Release();
return;
}
pp.Windowed = 1;
pp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;
pp.BackBufferFormat = ds.Format;
if (d3d8->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetForegroundWindow(),
D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, &dev) == D3D_OK)
{
if (dev)
{
//Копируем адреса виртуальных методов
origReset = *((DWORD*)(*(DWORD*)dev) + 14);
origPresent = *((DWORD*)(*(DWORD*)dev) + 15);
//console("address \"Reset method\" [%#x]", origReset);
//console("address \"Present method\" [%#x]", origPresent);
dev->Release();
d3d8->Release();
}
}
else
{
d3d8->Release();
return;
}
}
}
DWORD WINAPI InitThread(HINSTANCE hinstDLL)
{
//t_con.create();
GetDevice9Methods();
if (origReset && origPresent)
{
_tPresent = (tPresent)DetourCreate((PBYTE)origPresent, (PBYTE)HookedPresent, 5);
_tReset = (tReset)DetourCreate((PBYTE)origReset, (PBYTE)HookedReset, 5);
}
while (!GetAsyncKeyState(VK_END))
{
Sleep(1);
}
//t_con.del();
FreeLibraryAndExitThread(hinstDLL, 0);
return 1;
}
HRESULT WINAPI HookedPresent(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect,
CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
{
if (!pFont)
{
createFont(pDevice);
}
else
{
D3DX_Font(pDevice);
}
D3DRECT rec = { 10, 10, 30, 30 };
//pDevice->Clear(1, &rec, D3DCLEAR_TARGET, 0xFFFF0000, 1.0f, 0);
return _tPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT WINAPI HookedReset(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *params)
{
return _tReset(pDevice, params);
}
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH://Вызывается первым
CreateThread(0, 0, LPTHREAD_START_ROUTINE(InitThread), hinstDLL, 0, 0);
return 1;
case DLL_PROCESS_DETACH://вызывается после освобождения библиотеки
break;
case DLL_THREAD_ATTACH://вызывается при создании потока
break;
case DLL_THREAD_DETACH://вызывается после разрушения потока
break;
}
return TRUE;
}
Как пофиксить проблемы с нехваткой libci:
Скачать саму либу и заинклудить в проект;
Заинклудить дополнительные зависимости, как сказано тут.
Результат:
#ieee_754
Слышал, что при работе с числами с плавающей запятой возможна так называемая ошибка
двойного (повторного) округления (double rounding error), особенно когда имеют место
переходы от одинарной точности (float) к двойной (double) и наоборот. Как это понимать?
Ответы
Ответ 1 Эта ошибка мало известна в среде обычных профессиональных программистов, потому что
возникает она крайне редко, да и то в задачах с особой спецификой. Почти наверняка
вы никогда её не встретите. Но знать о ней нужно хотя бы для общего развития и повышения
культуры работы с арифметикой с плавающей запятой.
В чём суть ошибки?
Ошибка двойного округления иногда возникает в тех случаях, когда вместо одного округления
выполняется два последующих друг за другом округления. Рассмотрим пример в десятичной
системе счисления. У нас есть число 1,34999. Если мы сразу округлим его до одного знака
после десятичной запятой, то получим 1,3. Но если сначала округлить до двух знаков,
а потом до одного, то получим 1,35, а затем 1,4. Как мы видим, результаты получились
разными, причём существенно!
Как это связано с моей программой?
В вашей программе могут быть, как минимум три (больше я просто не знаю) места, где
может быть ошибка двойного округления.
Вы используете тип данных double размером 64 бита, но на вашем компьютере нет команд,
которые работают с double (или компилятор их не поддерживает), а есть только сопроцессор
x87. Таким образом, любая операция с double выглядит так: происходит расширение типа
с 64-х до 80-ти битов, затем, собственно, необходимые вычисления, в которых результат
округляется до 63-х битов дробной части мантиссы (такова структура 80-битового числа
с плавающей запятой), а затем происходит второе округление до 52-х битов дробной части
мантиссы в double.
Пример программы. Числа для кода я позаимствовал у @Mark Dickinson из англоязычного
SO. Вы знаете, что long double размером 80 битов в настоящий момент не поддерживается
(например, в VC++ точно), а заменяется на обычный double. Поэтому пример работать не
будет, если не указать специальную опцию компилятора, которая заставит его работать
через x87. У каждого компилятора своя такая опция (если вообще есть).
#include
int main (void) {
double a = 1e16 + 2.9999, b;
long double x = 1e16L, y = 2.9999L;
b = (double)(x+y);
printf ("a = %16.0lf, b = %16.0lf\n", a, b);
return 0;
}
Программа выдаст два разных целых числа: 10000000000000002 и 10000000000000004, показывая,
тем самым, разницу, возникшую в результате двойного округления.
Вы используете функции, которые созданы специально для double, но подаёте им на вход
числа float. Скажем, есть функция sqrt для double. Если передать ей на вход число float,
то произойдёт расширение его до double, затем функция вычислит результат с округлением,
а затем выполнится второе округление, если вы присваиваете результат обратно во float.
К сожалению, каких-то реальных примеров подобной ошибки мне отыскать не удалось, но
чисто теоретически любая подмена float на double и обратно может дать ошибку двойного
округления. Это будет хорошо видно на последнем, самом любопытном примере.
Данное наблюдение я подсмотрел в статье “Double Rounding Errors in Floating-Point
Conversions”, но сделал свой собственный пример. Общий смысл таков, что константа может
быть неверно преобразована в бинарный формат на этапе компиляции, если произойдёт двойное
округление. Это может произойти когда когда вы забыли суффикс f для чисел типа float
или если пользуетесь VC++ любой версии.
Для демонстрации за основу будет взято число 1+2-23+2-24-2-54. Оно равно 1.000000178813934270660723768742172978818416595458984375.
Это число интересно тем, что в двоичном формате оно равно
1,000000000000000000000010111111111111111111111111111111(2)
Полужирным шрифтом я отметил биты 24 и 53-54. Если читатель не знаком с правилами
округления чисел в формате IEEE-754, то ему придётся сначала их изучить. Например,
здесь. Если мы хотим перевести данное число в формат float, то никаких проблем нет:
24-й бит равен нулю, а значит округление до 23-х бит, необходимых float, произойдёт
вниз без вопросов. Получим число 1,00000000000000000000001, что в формате IEEE-754
будет иметь вид 0x3f800001. Если же мы сначала приводим число к типу double, то округление
до 52-х бит сначала произойдёт вверх, и мы получим 1,0000000000000000000000110000000000000000000000000000,
а затем, из-за того, что 23-й и 24-й биты теперь равны 1, в результате второго округления
до float получим 1,00000000000000000000010 (снова округление произошло вверх), что
в шестнадцатеричной записи будет иметь вид 0x3f800002. Как видно, мы получили два разных
числа.
Рассмотрим демонстрационный код (не плюйтесь, что в коде есть грязные трюки, здесь
я хочу просто и без хитростей показать биты числа):
#include
typedef unsigned int u32;
typedef unsigned long long u64;
int main (void) {
float a, b;
double c;
a = 1.000000178813934270660723768742172978818416595458984375f;
b = 1.000000178813934270660723768742172978818416595458984375;
c = 1.000000178813934270660723768742172978818416595458984375;
printf ("a = %08x, b = %08x, c = %016llx\n", *(u32*)&a, *(u32*)&b, *(u64*)&c);
return 0;
}
Здесь переменная a инициализируется правильно, мы используем суффикс f, инициализация
переменной b происходит так, будто программист забыл про суффикс f (к счастью, многие
компиляторы ему об этом напомнят), поэтому здесь произойдёт двойное округление (сначала
константа превратиться в double, а затем будет присвоена к float), а переменная c здесь
просто так, для демонстрации промежуточного округления в double. Функция printf выводит
шестнадцатеричный код всех трёх переменных. Компилятор Tiny C выдаёт верный ответ:
a = 3f800001, b = 3f800002, c = 3ff0000030000000
Такой же точно ответ выдали Intel C 15 и Clang.
Компилятор VC 2015 выдал
a = 3f800002, b = 3f800002, c = 3ff0000030000000
Это значит, что он ИГНОРИРУЕТ суффикс f, если он установлен, и в любом случае приводит
результат сначала к double, а потом к float, если нужно. По-хорошему, разработчики
компилятора заработали этим сильный удар линейкой по пальцам.
Копилятор GCC из MinGW выдал также неверный ответ
a = 3f800001, b = 3f800001, c = 3ff0000030000000
То есть с точки зрения исходного желания программиста ответ верный (и здесь он молодец,
что угадал это желание), но с точки зрения Стандарта - нет.
Что же теперь делать?
Повышайте культуру работы с числами с плавающей запятой, никогда не делайте необоснованного
расширения типа данных с тем, чтобы потом вернуться обратно. Да, зачастую это оправдано,
но оправдание должно быть не чисто интуитивным, а строго доказанным.
Будьте осторожны, и да минуют вас ошибки двойного округления.
#javascript #webpack #сборка
В проекте имеется директория frontend следующей структуры:
├── common
├── static
├── css
├── js
└── common.js
├── node_modules
├── package.json
├── app
├── static
├── css
├── js
└── script1.js
└── script2.js
└── webpack.config.js
Классы и некоторые методы, которые я определил в common.js, мне нужны в script1.js
и script2.js. Я их импортировал как
import './common/static/js/common.js'
import { Class1, Class2 } from './common/static/js/common.js'
Но при сборке webpack --display-error-details сообщает об отсутвующем модуле
ERROR in ./app/static/app/js/settings.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./common/static/js/common.js
in .../frontend/app/static/table/js resolve file
.../frontend/app/static/table/js/common/static/js/common.js doesn't exist
То есть webpack ищет файл в том же каталоге, где располгается вызывающий скрипт,
а не каталог frontend.
Я понимаю, что могу задать инструкцию импорта вида ../../../../../../script.js, но
это выглядит не очень.
Можно сделать так, чтобы webpack искал относительно заданного мной каталога, в данном
случае frontend?
Сейчас часть конфига с resolve выглядит так:
resolve: {
moduleDirectories: ['node_modules'],
extension: ['', '.js', '.styl']
},
Дополнение. Импорт прошел успешно только после того, как добавил в конфиг директорию
с импортируемым скриптом:
resolve: {
root: [
path.resolve('./common/static/js'),
],
moduleDirectories: ['node_modules'],
extension: ['', '.js', '.styl']
},
Почему добавляется в качестве корня этот каталог и не добавляется каталог, в котором
лежит конфиг?
Ошибка исправлена - неправильно записывал импорты. Настройки вебпака из ответа Утки
resolve: {
root: [
path.resolve(__dirname),
],
moduleDirectories: ['node_modules'],
extension: ['', '.js', '.styl']
},
Поправил импорт
import { capitalizeFirstLetter, formatString } from 'common/static/js/common.js';
import { elementByClass, elementById } from 'common/static/js/common.js'
Ответы
Ответ 1 Для webpack 1 (то есть текущего стабильного документированного) нужно добавить root
в секцию resolve:
var path = require('path');
resolve: {
root: [
path.resolve('yourRoot')
]
},
yourRoot - расположение желаемого корня. Например текущую директорию для webpack.config.js
можно взять так: path.resolve(__dirname)
path - родной нодовский модуль, ставить отдельно не надо.
#cpp #qt #qt5
Некоторая программа постоянно дописывает определённое кол-во строк в N-е число файлов.
Мне необходимо в цикле проверять изменился ли файл, и если в него что-то дописали,
то считать эту информацию. Все файлы имеют обычное расширение txt.
Существует ли уже готовое решение во фрейморке qt? так сказать "из коробки".
Ответы
Ответ 1 Есть такой велосипед tail из GNU core utilities.
# dpkg -S `which tail`
coreutils: /usr/bin/tail
Можно запустить tail -F /var/log/*.log, -F - флаг говорит утилите следить за изменениями.
Таким образом Ваша задача решается.
Сырцы tail на c: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/tail.c
Кошмарные конечно, но всего 2400 строк.
2234 int main (int argc, char **argv) {
там заполняются хидеры( заголовки ) потом на строке
2328 for (i = 0; i < n_files; i++) ok &= tail_file (&F[i], n_units);
запускается матрёшка из tail-ов на файлы, которые уже в заголовках лежат.
1885 static bool tail_file (struct File_spec *f, uintmax_t n_units) {
внутри вызывается просто tail()
1871 static bool tail (const char *filename, int fd, uintmax_t n_units, uintmax_t
*read_pos)
там вызывается tail_lines()
1809 static bool tail_lines (const char *pretty_filename, int fd, uintmax_t n_lines,
uintmax_t *read_pos)
И дальше там просто lseek-ами куски вытягиваются... Вообщем, может поможет.
В крайнем случае, можно запустить tail -F {Ваш,Список,Файлов} как subprocess, и ловить
pipe с него...
#cpp #visual_studio #строки #сортировка
Нужно отсортировать слова, например: ёжик, Азбука, аромат, Ёж. Проблема в том, что
буква ё не сортируется.
#include
#include
#include
#include
#include
#include
using namespace std;
int main() {
int element;
string number;
cin >> element;
auto l = list();
for (int i = 0; i < element; i++) {
cin >> number;
l.push_back(number);
}
l.sort();
for (auto iterator = l.begin(); iterator != l.end(); ++iterator)
{
cout << *iterator << endl;
}
return 0;
}
Ответы
Ответ 1 При сортировке списка из string строки сравниваются по-символьно (побайтно). В зависимости
от типа кодирования байт будут разные результаты сравнения. Во всех популярных кодировках,
а именно в Unicode, CP866 (DOS), CP1251 (Windows) во всех у них буква Ё/ё стоят где-то
в отдельном месте от алфавита, это означает сравнение букв не будет давать порядок
как в эталонном русском алфавите. Но проблема решаема, т.к. у функции сортировки можно
указать свою функцию сравнения элементов. l.sort([](string const & l, string const
& r)->bool{ /* Сравнить l и r */ }); при этом нужно реализовать код внутри так чтобы
сравнить две строки l и r учитывая специфику буквы Ё/ё, код должен возвращать true
если l < r иначе false. Также чтобы решить проблемы с кодировками можно просто в каком
то виде вначале прочитать строки, а потом их сконвертировать в Unicode и уже в юникоде
делать сравнения, либо привязаться к какой то кодировке, это не важно в какой кодировке
Ё/ё по особому сравнивать. Вот привожу почти весь нужный код, подходит для строк в
кодировках CP866 и CP1251 (для юникода тоже вполне может подойти только вместо char
нужно uint32_t или char32_t):
// Где-то выше определить функцию CharOrder.
inline uint32_t CharOrder(char c) {
if (c == 'ё') return uint32_t(uint8_t('е')) * 2 + 1;
if (c == 'Ё') return uint32_t(uint8_t('Е')) * 2 + 1;
return uint32_t(uint8_t(c)) * 2;
}
....
// Где нужно сортировать список l из строк, написать.
l.sort([](std::string const & a, std::string const & b)->bool{
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), [](char
a, char b)->bool{
return CharOrder(a) < CharOrder(b);
});
});
Ответ 2 #include
#include
#include
#include
#include
#include
template
static void PrintList(const std::list& l)
{
std::cout << "List: ";
for (auto iterator = l.begin(); iterator != l.end(); ++iterator)
{
std::cout << *iterator << " ";
}
std::cout << std::endl;
}
int main(int argc, const char * argv[]) {
system("chcp 1251");
std::list l = { "ёлка", "Еда", "аббат", "жеод" };
PrintList(l);
l.sort(std::locale(""));
PrintList(l);
return 0;
}
#net #рефлексия #f#
Заинтересовал вопрос как получить информацию о функциях которые содержит модуль.
Хочу получить что-то вроде того, что выдает FSI.
Например для следующего модуля
module Test =
let ign _ = ()
let getNowDateTime() = System.DateTime.Now
let getNumbers count = [1..count]
FSI выводит такую информацию
module Test = begin
val ign : 'a -> unit
val getNowDateTime : unit -> System.DateTime
val getNumbers : count:int -> int list
end
Пробовал достать данные через рефлексию следующим образом
let getInfoAboutModule (t : Type) =
let genericToString (t : Type) =
match t.GenericTypeArguments with
| [| |] -> t.FullName
| x ->
x
|> Seq.map (fun x -> x.Name)
|> String.concat ","
|> sprintf "%s<%s>" t.Name
let getInfo (mi:MethodInfo) =
let parameter =
let sb = System.Text.StringBuilder()
for x in mi.GetParameters() do
x.ParameterType
|> genericToString
|> sprintf "%s : %s ->" x.Name
|> sb.Append
|> ignore
sb.ToString()
|> fun str -> if str |> System.String.IsNullOrEmpty then "unit -> " else str
sprintf "%s : %s %s" mi.Name parameter (genericToString mi.ReturnType)
t.GetMethods(BindingFlags.Public ||| BindingFlags.Static)
|> Seq.map getInfo
для модуля Test результат будет следующим
ign : _arg1 : -> System.Void
getNowDateTime : unit -> System.DateTime
getNumbers : count : System.Int32 -> FSharpList`1
MCVE (ideone)
но, естественно, таким образом получаю названия далекие от F#-ных.
P.S. Добавлять какие-либо атрибуты к модулю нельзя, т.к. нужно оставить возможность
извлекать данные из модулей из других сборок.
Ответы
Ответ 1 Можно воспользоваться FSharp.Compiler.Service для анализа исходных текстов модулей.
Если модуль скомпилирован и его исходных текстов нет, то сомневаюсь, что можно добиться
лучшего результата, чем ваш.
На основе этого примера:
open System
open System.IO
open Microsoft.FSharp.Compiler.SourceCodeServices
let text =
"""
module Test =
let ign _ = ()
let getNowDateTime() = System.DateTime.Now
let getNumbers count = [1..count]
"""
let checker = FSharpChecker.Create()
// из примера
let parseAndTypeCheckSingleFile input =
let file = "test.fsx"
let projOptions =
checker.GetProjectOptionsFromScript(file, input)
|> Async.RunSynchronously
let parseFileResults, checkFileResults =
checker.ParseAndCheckFileInProject(file, 0, input, projOptions)
|> Async.RunSynchronously
// Wait until type checking succeeds (or 100 attempts)
match checkFileResults with
| FSharpCheckFileAnswer.Succeeded(res) -> parseFileResults, res
| res -> failwithf "Parsing did not finish... (%A)" res
// печать информации о члене модуля
let printInfo (fn:FSharpMemberOrFunctionOrValue) =
// строка с информацией о типе
let rec getTypeString (t:FSharpType) =
if t.HasTypeDefinition then
let prms = [ for x in t.GenericArguments -> (getTypeString x) ] in
t.TypeDefinition.DisplayName +
" " +
String.Join(" ", prms)
else
t.ToString()
printf "%s: " fn.DisplayName
for group in fn.CurriedParameterGroups do
for prm in group do
match prm.Name with
| None -> ()
| Some name -> printf "%s:" name
printf "%s -> " (getTypeString prm.Type)
printf "%s\n" (getTypeString fn.ReturnParameter.Type)
[]
let main argv =
let parseFileResults, checkFileResults =
parseAndTypeCheckSingleFile text
let m = checkFileResults.PartialAssemblySignature.Entities.[0]
let fns = m.NestedEntities.[0].MembersFunctionsAndValues
for x in fns do printInfo x
0
Результат:
ign: type 'a -> unit
getNowDateTime: unit -> DateTime
getNumbers: count:int -> list int
Либо можно поизучать исходники непосредственно FSI.
Если возникает ошибка при парсинге, нужно скопировать файлы FSharp.Core.optdata и
FSharp.Core.sigdata в каталог с программой. Файлы можно найти в %PROFRAMFILES%\Reference
Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.4.0.0\.
#php #linux #сервер #веб_сервер #memory
Проблема собственно вот в чем: мои скрипты php после отработки засоряют оперативную
память сервера,но не все конечно. Системный администратор после изучения этой темы
говорит что память засоряется после моих скриптов и они являются активными процессами(
как я понял спящими по букве S)
Я прекрасно понимаю, что вы не волшебники и не можете проинтуичить без выкладки кода,
но может кто то сталкивался с подобными проблемами. Хотелось бы понять алгоритм нахождения
ответа. Может он заключается в том чтобы прозвонить код на количество резервируемой
под него памяти, найти самый прожорливый участок и оптимизировать его.
Даже если это будет выполнено, памяти будет жрать меньше, но причина похоже не в
этом. Может необходимо найти конфигурационный файл сервера и обратить внимание на конкретные
строки параметров? В зависимости от ситуации я добавлю сюда необходимую информацию
Или может добавлять какуюто строку кода в php скрипт чтобы сервер убивал соединение?
Да кстати в циклах использую
break;
Также использовал
ini_set('memory_limit', '1024M');
Но после закоменчивания этой строки изменений не было. Или может жестко поступить
- найти все переменные и сделать
unset($some_param);
Откуда начинать копать? Статьи по оптимизации кода читал, применяю их на практике,
но как известно в этом направлении можно далеко уйти и писать на Ассемблере
Добавлено минутой позже:
Также использую в коде
exit();
в том случае если код не имеет смысла дальше выполнять - или вместо него необходимо
использовать
die();
Добавлено 5 минутами позже:
Это веб сервер.
Пользователь загружает фаил эксель для парсинга и получается вышеописанное
NGINX 1.6.2 PHP5-FPM без APACHE
5.6 PHP версия
Добавлено через 9 часов:
на форуме говорится о команде
strace -p
которая показывает что хочет выполнить процесс в нашем случае PID 10354. Это конечно
не ответ на вопрос, но может поспособствовать его решению.
На ресурсе сказано что данный режим может быть вызван недостатком мощностей процессора(но
по сути какой бы мощный процессор не был, нагрузить его на 100% можно), также сказано
что такое поведение наблюдается когда в коде php есть команда
sleep($count_of_seconds);
Да - данная команда ввергает процесс в состояние Sleep, но здесь нет зависимости
от количества потребляемой памяти.
Как мне объяснил системный администратор - сколько пользователей на сайте, столько
будет спящих www-data, следовательно состояние sleep вполне нормально, ненормально
количество удерживаемой для этого процесса памяти.
Добавлено 22,02,2017
Вот что происходит когда остаются 3 спящих процесса
Ответы
Ответ 1 Моя история похожа.
Конфигурация: nginx+php-fpm
Тяжелый запрос на бекенде и при заходе на него 3-5 раз подряд, память забивалась
и вылетала ошибка:
502 bad gateway
При этом память сама не отчищалась.
Мой конфиг до проблемы:
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 25
pm.max_requests = 500
Конфиг после:
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500
Попробуйте так.
Ответ 2 Считаю 374 мегабайта RES совершенно нормальным значением для php-fpm.
То есть, на мой взгляд, у вас проблема совершенно не в вашем коде, а либо в использовании
PHP как такового, либо просто в неадекватной задачам конфигурации сервера (мало RAM
для запущенного набора процессов).
Ответ 3 Тут оказывается не только дело в скриптах но и в настройках php-fpm а именно надо
поиграться с настройками
/etc/php5/fpm/pool.d/www.conf
а именно
pm.max_requests
request_terminate_timeout
request_terminate_timeout устанавливает максимальное время выполнения дочернего процесса,
прежде чем он будет уничтожен. Это позволяет избегать долгих запросов, если по какой-либо
причине было изменено значение max_execution_time в настройках интерпретатора. Значение
стоит установить исходя из логики обрабатываемых приложений, скажем 60s (1 минута).
#pip
В консоле windows ввожу команду pip install cpickle
Collecting cpickle
Downloading cpickle-0.5.tar.gz
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "c:\users\kaz19\appdata\local\programs\python\python35\lib\tokenize.py",
line 454, in open
buffer = _builtin_open(filename, 'rb')
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\kaz19\\AppData\\Local\\Temp\\pip-build-nnts2rx3\\cpickle\\setup.py'
Как это исправить?
Ответы
Ответ 1 Оказывается в python 3.5 он уже установлен и называется просто pickle
#css #css3
Здравствуйте.
Если к элементу применить CSS свойство transform: rotate(45deg) он развернется, но
положение в потоке не изменит
Возможно ли сделать так, чтобы границы блока пересчитались и рассчитывались по углам,
например так:
Ответы
Ответ 1 Вызов .getBoundingClientRect() всегда возвращает актуальные габариты элемента, в
т. ч. после трансформации. Нам понадобятся его свойства width и height. Чтобы центр
вращения всегда был внутри внешней обертки нам надо выровнять его по вертикали и горизонтали,
для этого поставим обертке свойство display: inline-flex, а самому элементу margin:
auto. Далее, при каждом вращении будем устанавливать ширину и высоту вращаемого элемента
обертке.
let rotationAngle = 0,
el = document.querySelector('.el'),
wrapper = document.querySelector('.wrapper');
recalcDimensions(30);
document.querySelector('.rotator').addEventListener('click', recalcDimensions.bind("",
5));
function recalcDimensions(rotateAngle) {
rotationAngle += rotateAngle;
el.style.transform = "rotate(" + rotationAngle + "deg)";
let w = el.getBoundingClientRect().width,
h = el.getBoundingClientRect().height;
wrapper.style.width = w + 'px';
wrapper.style.height = h + 'px';
}
.wrapper {
display: inline-flex;
background-color: #000;
position: relative;
}
.el {
display: block;
margin: auto;
width: 250px;
height: 250px;
background-color: #ccc;
}
.rotator {
position: absolute;
right: 10px;
top: 10px;
padding: 10px 20px;
}
rotate me!
Ответ 2 div {
position: relative;
}
div::after,
div::before {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
}
div::after {
background-color: rgba(0, 255, 0, .3);
}
div::before {
background-color: rgba(0, 0, 255, .3);
transform: rotate(45deg) scale(.70711356, .70711356);
}
#c_sharp #aspnet #dll
Добрый день. Мне нужно из моей dll передать объект класса, реализующего такой интерфейс:
public interface IDataProvider
{
void InitPhone();
List GetPhone();
string Print();
}
передать в мое основное приложение. В основном приложении я так же описал данный
интерфейс. В dll написан вот такой код который возвращает реализацию данного интерфейса:
public class CreateInstance
{
public IDataProvider GetDataProvider()
{
IDataProvider provider = new DataProvider();
return provider;
}
}
А в основном приложении данная библиотека подключается при помощи assembly meneger
и вызывается, таким вот образом:
public class DataModuleInterface
{
Object o;
Type t;
Assembly ass;
public DataModuleInterface()
{
var binFolder = new DirectoryInfo(Path.Combine(@"C:\Users\Neoniklain\Source\Repos\KemSU_Shedule\Shedule\Shedule\Modules"));
foreach (var file in binFolder.GetFileSystemInfos("*.dll", SearchOption.AllDirectories))
{
ass = AssemblyLoadContext.Default.LoadFromAssemblyPath(file.FullName);
Type[] AssemlyResource = ass.GetExportedTypes();
Type type= AssemlyResource[0];
foreach (var item in AssemlyResource)
{
if(item.Name=="CreateInstance")
{
t = ass.GetType(item.FullName);
}
}
o = Activator.CreateInstance(t);
}
}
public IDataProvider GetProvider()
{
MethodInfo m = ass.GetType(t.ToString()).GetMethod("GetDataProvider");
IDataProvider res = (IDataProvider)m.Invoke(o, null);
return res;
}
}
Ошибка возникает вот в этом месте:
IDataProvider res = (IDataProvider)m.Invoke(o, null);
И содержит следующий текст:
System.InvalidCastException:
"Unable to cast object of type 'Shedule.Module.DataModule.DataProvider'
to type 'Shedule.Module.DataModule.IDataProvider'."
Здесь стоит сказать что hedule.Module.DataModule - это моя библиотека, из которой
я хочу получить тот самый злосчастный класс.
Ответы
Ответ 1 В основном приложении я так же описал данный интерфейс.
У Вас определение интерфейса существует в двух местах, что для .NET означает два
разных типа.
Поместите тип интерфейса в третью библиотеку и ссылайтесь на нее из первых двух.
P.S.
А кто из присутствующих когда-нибудь получал такое сообщение об ошибке:
Cannot assign TFont to TFont.
?
#html #css #вёрстка
Такая проблема, есть макет https://jsfiddle.net/61htzzrx/
header {
background-color: #FBD293;
border-bottom: 1px solid #000;
height: 50px;
}
.middle {
border-right: 1px solid #000;
margin: 0 auto;
min-height: calc(100% - 50px);
overflow: hidden;
position: relative;
width: 600px;
background-color: #fff;
}
.middle > .left-sidebar {
background-color: #CBE6A3;
border-right: 1px solid #000;
box-sizing: border-box;
display: block;
float: left;
min-height: calc(100vh - 50px);
padding-bottom: 160px;
width: 100px;
}
.left-sidebar > .blocks {
background: #e6a3a3;
height: 400px;
}
.middle > .content {
background: #A3CCFF;
display: block;
float: left;
min-height: calc(100vh - 50px);
width: 500px;
}
.left-sidebar footer {
height: 100px;
bottom: 0;
position: absolute;
background: #D6A3E6;
}
Контент, должен быть прижат к низу
Надо прижать .content к низу и сделать так, чтобы меню всегда оставалось на виду
(перемещалось вместе с прокруткой)
Сейчас у меня такие проблемы:
1) Черная полоска справа от aside идет не до конца страницы, и фон aside тоже
2) .blocks должен прокручиваться вместе со страницей и не залезать на footer
Ответы
Ответ 1 Сайдбар клеится внутрь блока при помощи position: sticky, для кроссбраузерности не
забудьте использовать полифилл.
Остальное — флексбокс.
*,
*:after,
*:before {
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
align-items: center;
}
header {
background-color: #FBD293;
border-bottom: 1px solid #000;
height: 50px;
width: 600px;
}
.middle {
border-right: 1px solid #000;
margin: 0 auto;
width: 600px;
background-color: #fff;
display: flex;
flex-grow: 1;
}
.left-sidebar {
position: relative;
background-color: #CBE6A3;
border-right: 1px solid #000;
display: flex;
flex-direction: column;
flex-basis: 100px;
}
.left-sidebar__blocks-holder {
position: relative;
flex-grow: 1;
}
.blocks {
background: #e6a3a3;
height: 400px;
position: sticky;
top: 0;
}
.content {
background: #A3CCFF;
min-height: 800px;
flex-grow: 1;
}
.left-sidebar footer {
height: 100px;
background: #D6A3E6;
}
Контент, должен быть прижат к низу
Ответ 2 Вот пример по тем критериям которые вы сказали что хотите поправить:
Это стандартная верстка CSS не знаю что объяснить, если будут вопросы скажите.
Вот код:
body{
margin: 0;
}
header {
background-color: #FBD293;
border-bottom: 1px solid #000;
height: 50px;
}
.middle {
border-right: 1px solid #000;
margin: 0 auto;
min-height: calc(100% - 50px);
overflow: hidden;
position: relative;
width: 600px;
background-color: #fff;
}
.middle > .left-sidebar {
position: fixed;
top: 0;
z-index: 1000;
background-co
background-color: #CBE6A3;
border-right: 1px solid #000;
box-sizing: border-box;
display: block;
width: 100px;
height: 100%;
}
.left-sidebar > .blocks {
background: #e6a3a3;
height: 100%;
}
.middle > .content {
position: relative;
background: #A3CCFF;
display: block;
float: left;
min-height: calc(100vh - 50px);
width: 500px;
padding-left: 100px;
padding-bottom: 50px;
}
.content_footer{
position: absolute;
bottom: 0;
width: 100%;
height: 50px;
background: yellow;
}
body>footer {
height: 100px;
background: #D6A3E6;
}
#cpp #qt #qt5 #лицензирование
Просто хочу узнать правильно ли я думаю. Допустим я создал релизный exe файл, разместил
нужные Qt библиотеки для запуска в папке. Программа под лицензией LGPL. Я кидаю в папку
проги файл лицензии LICENSE.txt c описанием лицензии http://www.gnu.org/licenses/lgpl.html .
Достаточно этого чтобы распространять прогу?
Я хочу добавить еще свои условия дополнительно, например:
"Данное програмное обеспечение используется вами на свой страх и риск. Автор не несет
ответственности за возможные нежелательные последствия в случае применения данного
програмного обеспечения." Ну я еще хочу написать что то типа что доступ к вашей файловой
системе не будет использован хакерами и т.д.
Я конечно все переведу на English. Так вообще правильно?
И Inno Setup делаю установщик с файлом этой лицензии.
Ответы
Ответ 1 Достаточно этого чтобы распространять прогу?
Недостаточно. Коротко по пунктам:
Qt использует не LGPL, a LGPLv3 - это важно!
Согласно п.4 LGPLv3, кроме помещения текста оригинальной (без перевода) лицензии
- нужно в исполняемый файл добавить ссылку/пункт, в котором есть упоминание об использовании
библиотеки и лицензии, а так же ссылку/пункт, по которому текст лицензии будет доступен
из приложения. Обычно это делается в диалоге "О программе". А лучше самостоятельно
изучить этот пункт лицензии и выполнить все его требования, там их немного.
Можно распространять программу по нескольким лицензиям одновременно, например, LGPLv3
и вашей собственной. Но следует учесть, что вы должны обеспечить отсутствие конфликтов
лицензий. Иными словами, не должно быть ни одного взаимоисключающего требования между
всеми лицензиями одновременно. Тем не менее, запрещать допущения из других лицензий
(налагать свои непротиворечащие требования) - вы вправе.
Я конечно все переведу на English
Свою лицензию вы вольны оставлять на любом языке. Но есть нюанс. Действующей лицензией
считается только лицензия на одном языке (это орининал). Какой это будет язык - решать вам.
#java #коллекции #concurrency
Vector, HashTable, Stack являются устаревшими коллекциями, и пишут что их не используют
в виду синхронизированности их методов. В чем минус синхронизации? Если однопоточная
среда, это как-то влияет на их работу? Потокобезопасность это же хорошо. Если они устаревшие,
зачем создавали синхронизированные коллекции в concurrent пакете?
Извините за тупой вопрос, очень интересно просто. Заранее спасибо.
Ответы
Ответ 1 Потокобезопасность это же хорошо.
Потокобезопасность не бесплатна, точнее очень не бесплатна, именно поэтому есть потокобезопасные
и не потокобезопасные коллекции.
Если однопоточная среда, это как-то влияет на их работу?
Такие коллекции работают значительно медленее, чем не синхронизированные аналоги
Если они устаревшие, зачем создавали синхронизированные коллекции в
concurrent пакете?
Новые синхронизированные коллекции используют более быстрый алгоритм, когда блокируется
не вся коллекция целиком при каждом чихе, а только часть (блок), поэтому Vector, HashTable,
Stack не стоит использовать ни в многопоточности (они работают медленнее, чем новые
коллекции), ни в однопоточном - они просто избыточны.
Если интересно более подробно разобраться с коллекциями советую посмотреть мою статью
P.S. В принципе, если вам производительность не важна, то ничего страшного не случится
если вы будите использовать Vector, HashTable и т.п. вместо ArrayList, HashMap и т.д.,
они будут работать нормально. Но их использование считается плохим кодом и признаком
плохого знания языка.
#javascript #jquery
Если встречается согласная буква, то пропускать одну позицию в строке, если встречается
гласная - то две.
В итоге должно получится слово hello. Проблема в том, что значение в pos после первого
раза не меняется, как это поправить?
var str = "hieeelalaooo"; //строка
var vowels = "aeiouy"; //гласные
var pos=0, res;
var res = str.charAt(0);
for (var i = 0; i <= str.length; i++) {
for (var j = 0; j <= vowels.length; j++) {
if (pos == i) continue;//если есть позиция букву которой мы взяли то пропускаем
if (str[i] != vowels[j]) {//если согласная то
pos = i + 2;//позиция увеличивается на два
} else {
pos = i + 3;//если гласная то на три
}
}
res += str[pos];//получаем букву
console.log(res)
}
Ответы
Ответ 1 Наличие символа в массиве гласных можно делать с помощью indexOf, т.е. по факту вам
не нужны 2 цикла с тремя счетчиками.
var str = "hieeelalaooo"; //строка
var vowels = "aeiouy"; //гласные
var pos, res = "";
var i = 0;
while (i < str.length) {
res += str[i];
if(vowels.indexOf(str[i]) > -1) {
i += 3;
} else {
i += 2;
}
}
console.log(res);
Ответ 2 Ошибка в логике: вместо того, чтобы определить гласная буква или согласная, на каждую
букву pos меняется столько раз, сколько букв в массиве vowels
Кроме этого:
проблемы со счетчиками (i <= str.length;, j <= vowels.length;) - в случае когда счетчик
равен str.length, str[i] будет равен undefined, так как индексация идет с нуля.
строка res меняется после изменения pos, но до проверок, что pos не выходит за границы
строки. Поэтому в конце результата выводится много undefined
if (pos == i) continue; - бесполезное условие, которое всегда false
непонятно как связан счетчик i с переменной pos.
Если убрать недочеты, то может получиться так:
// Если встречается согласная буква, то пропускать одну позицию в строке, если встречается
гласная - то две.
var str = "hieeelalaooo"; //строка
var vowels = "aeiouy"; //гласные
var res = '';
for (var pos = 0; pos < str.length;) {
res += str[pos];
var isVowels = false;
for (var j = 0; j < vowels.length; j++) { // проверяем тип буквы
if (str[pos] == vowels[j]) { // если гласная
isVowels = true; // выставляем флаг
break; // выходим
}
}
if (isVowels) {
pos += 3;
} else {
pos += 2;
}
console.log(res)
}
вместо внутреннего цикла, можно воспользоваться методом indexOf как в ответе @br3t
либо перевести строку в объект, с ключами соответствующими гласным буквам и использовать его:
// Если встречается согласная буква, то пропускать одну позицию в строке, если встречается
гласная - то две.
var str = "hieeelalaooo"; //строка
var vowels = "aeiouy".split('').reduce((acc, el) => acc[el] = true && acc, {}); //гласные
var res = '';
for (var pos = 0; pos < str.length;) {
res += str[pos];
if (vowels[str[pos]]) {
pos += 3;
} else {
pos += 2;
}
console.log(res)
}
Ответ 3 var str = "hieeelalaooo"; //строка
var vowels = "aeiouy"; //гласные
var vowels = new Set(vowels.split(''));
var res = '';
for (var i = 0; i < str.length; i++) {
if (str[i] === ' ')
res += str[i++];
res += str[i];
i = vowels.has(str[i]) ? i + 2 : i + 1;
}
console.log(res);
Ответ 4 var str = "hieeelalaooo";
var vowels = 'aeiouy';
var word = '';
for (var i = 0; i < str.length; i++) {
if (str[i] == ' ') {
word += ' ';
} else if(vowels.indexOf(str[i]) > -1 ) {
word += str[i];
i += 2;
} else {
word += str[i];
i++;
}
}
console.log(word);
Ответ 5 => что-то типа того, осмысленней и по-современней, чем предлагали выше:
{
const str = "hieeelalaooo"; //строка
const glass = "aeiouy"; //гласные
const res = [];
str.split('').forEach(e=>
glass.split('').includes(e) && !res.includes(e) ? res.push(e):''
)
console.log('гласные не повторяющиеся -> '+res.join(''));
}
///////еще короче:
{
const str = "hieeelalaooo"; //строка
const glass = "aeiouy"; //гласные
str.split('').reduce( (sum,e) =>glass.split('').includes(e) && !sum.includes(e) &&
sum.push(e)&&sum||sum, []
)
}
#c_sharp
This question already has answers here:
Составной ключ в Dictionary
(4 ответа)
Closed 2 года назад.
public class Pair
{
public FT x;
public ST y;
public Pair()
{ }
public Pair(FT a, ST b)
{
x = a;
y = b;
}
}
Dictionary,int> used = new Dictionary, int>();
Есть код выше. Я добавляю в used данные таким образом
used[new Pair(x, y)] = 1;
И когда хочу проверить used.ContainsKey(new Pair(x, y)), то всегда выдается
false, даже тогда, когда такие же x,y уже есть. Просто добавляются еще раз. С чем это
может быть связано?
Ответы
Ответ 1 Dictionary для того, чтобы обращаться к элементу по ключу, необходимо сравнивать
ключи друг с другом.
Вы должны реализовать операцию сравнения двух объектов класса Pair, например,
реализовав интерфейс IEquatable>, либо, переопределив метод object.Equals
и object.GetHashCode.
Пример реализации IEquatable>:
public class Pair : IEquatable>
{
private FT x;
private ST y;
public Pair()
{ }
public Pair(FT a, ST b)
{
x = a;
y = b;
}
public bool Equals(Pair other)
{
return EqualityComparer.Default.Equals(x, other.x)
&& EqualityComparer.Default.Equals(y, other.y);
}
public override bool Equals(object other)
{
if (other is Pair)
return Equals((Pair)other);
return false;
}
public override int GetHashCode()
{
return EqualityComparer.Default.GetHashCode(x)
^ EqualityComparer.Default.GetHashCode(y);
}
}
Тонкий момент заключается в том, что эта операция сравнения не будет работать, если
у типов FT и ST также нет реализации IEquatable или не переопределён метод object.Equals.
UPDATE
Как здесь ниже справедливо дописали в комментариях, при реализации IEquality Microsoft
рекомендует также переопределить методы Equals и GetHashCode, а также операторы == и !=.
Так что самый дешёвый способ, это переопределить методы Equals и GetHashCode. Добавил
изменения в код.
#javascript
Как перебрать все свойства объекта, преобразовать их неким образом и вернуть преобразованный
объект?
есть объект такой
"object": {
"user": "admin",
"date": "14877890",
"last": "SKIPPED"
}
Нужно преобразовать date в дату и получить новый объект
Ответы
Ответ 1 Вот пример с функцией map для прохождения по объекту, и преоброзования timestamp в date
var object = {
"user": "admin",
"date": "14877890",
"last": "SKIPPED"
}
function timestamp2date(timestamp) {
var theDate = new Date(timestamp * 1000);
return theDate.toGMTString();
}
Object.keys(object).map(function(objectKey, index) {
var value = object[objectKey];
if(objectKey == 'date'){
console.log(timestamp2date(value));
}
});
#javascript #google_chrome #chrome_extension
Здравствуйте.
Хочу реализовать переключение между вкладками Google Chrome в своём расширении. Расширение
уже узнаёт id вкладок и может их обновлять.
Возможно ли сделать переключение между необходимыми мне вкладками, зная их tabId?
Ответы
Ответ 1 Для этого используйте updateProperties в методе .update():
chrome.tabs.update(tabId, { active: true });
#cpp #boost #геолокация
Имеется прорисовка пути маршрута автобуса выполненная при помощи массива точек (широта,
долгота) которые затем через leaflet прорисовываются у клиента
Делалось это все просто для визуального отображения маршрута в GPS мониторинге.
Теперь понадобилось контролировать съезд с маршрута как можно менее затратно в плане
ресурсов.
План таков, преобразовать каким то образом трансформировать точки в полигон и уже
через boost::geometry::intersects сверять находится ли машина на маршруте или нет при
поступлении свежих координат.
Идея по трансформации только такая, брать 2 точки добавлять по 10 метров отступа
слева и создавать полигон.
Проблема в том что точек на маршруте бывает под 1000..сомневаюсь что работать будет
быстро..может как то можно отсеять лишние точки
Ломаю голову..
Может есть что то готовое для подобной задачи?
Прошу помощи
Ответы
Ответ 1 А зачем возиться с полигонами?
У вас есть массив точек маршрута.
Каждая пара соседних точек определяет отрезок, часть маршрута.
Определить, к какому отрезку ближе всего точка
Вычислить кратчайшее расстояние до него (длинна перпендикуляра)
Если оно больше максимального заданного расстояния Lmax - зафиксировать съезд с маршрута
#windows #visual_studio #visual_cpp
Чисто случайно обнаружил, что среди сообщений об ошибках Windows много ошибок vctip.exe.
Начал копать, выяснил, что это что-то в составе Visual C++ 2015, но что эта программа
делает - в Интернете не пишут (или я не нахожу). Подсунул вместо нее заглушку - ей
не передается никакая информация (ни в командной строке, ни через стандартный ввод).
Вызывается при компиляции, но самой компиляции не мешает.
Стало просто интересно. Кто-то может подсказать, что это и зачем?
PS
File : vctip.exe
SHA256 : 46f89793d5df3ca4a24e1b1ee196ea150b105a7e10947c57e336509a12731c2f
SHA1 : 3648f03dc77946835fce7b54f358434a6f13bbc3
MD5 : fd442c307bc454d3930eaf6ec878fd36
CRC32 : cfa16112
Ответы
Ответ 1 Согласно данному ответу на форуме поддержки, это клиент телеметрии, который отправляет
в Microsoft сведения о выполняемых в студии действиях и возникающих ошибках (Visual
Studio Customer Experience Improvement Program). Ему ничего не передается через командную
строку, потому что он берет всю информацию в режиме реального времени из Event Tracing
for Windows.
Visual Studio Customer Experience Improvement Program по умолчанию включена, но ее
можно отключить способом, описанным здесь:
В меню выбрать Справка -> Отправить отзыв -> Параметры.
Выбрать параметр "Нет, я не хочу участвовать"
#c_sharp #c_sharp_70
Существует ли какой-либо способ расширить встроенный прямоугольный массив в c#?
Например:
public class Array2D:????
{
private T[,] _data;
public Array2D(T[,] vals)
{
_data = vals;
}
public IEnumerable Row( int iRow)
{
return _data.Cast().Select((t, j) => _data[iRow, j]);
}
}
Ответы
Ответ 1 Использовать методы расширения?
public static class TwoDimensionalArrayExtensions
{
public static IEnumerable Row(this T[,] array, int iRow)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
if (iRow < array.GetLowerBound(0) && iRow > array.GetUpperBound(0))
{
throw new ArgumentOutOfRangeException(nameof(iRow));
}
for (int columnIndex = array.GetLowerBound(1); columnIndex <= array.GetUpperBound(1);
columnIndex++)
{
yield return array[iRow, columnIndex];
}
}
}
Использование:
static void Main(string[] args)
{
var array = new int[2, 2] { { 1, 2 }, { 3, 4 } };
foreach (var value in array.Row(0))
{
Console.WriteLine(value);
}
}
#cpp #language_lawyer
Пусть есть структура S следующего вида:
struct S
{
short a;
char b;
};
И размер sizeof(short) равен 2, а размер sizeof(S) равен 4 (т.е. в структуре есть
один padding byte).
Вопрос 1. Является ли корректным с точки зрения стандарта языка такой код:
S st;
st.a = 0; st.b = 0;
unsigned char *p = reinterpret_cast(&st);
for (size_t i = 0; i != sizeof(st); ++i)
unsigned int tmp = p[i];
Вопрос 2. Если код корректен, то гарантируется ли, что в ситуации, когда указатель
p указывает на padding byte структуры S, в переменную tmp будет записано некоторое
целочисленное значение из отрезка [0; UCHAR_MAX] или допускаются какое-нибудь менее
очевидное поведение, например, генерация исключения.
Дополнение.
Действительно, если есть объект тривиально-копируемого типа T, то составляющие его
байты могут быть безопасно скопированы (например, с помощью memcpy) в массив char,
unsigned char или std::byte (и обратно). Также можно скопировать некоторый объект тривиально-копируемого
типа в другой объект этого же типа (с помощью того же самого memcpy, например.)
Однако, в пункте 11.6/12 (n4659) есть занятный пример:
unsigned char c;
unsigned char d = c; // OK, d has an indeterminate value
int e = d; // undefined behavior
Не является ли мой пример, в некотором смысле, эквивалентом этого примера из стандарта?
Ответы
Ответ 1 1) Да, каст к char* и unsigned char* разрешен (а каст к другим типам запрещен правилами
aliasing)
2) Нет для int.
Паддинг можно читать-писать (иначе memcpy сломался бы).
Однако, стандарт разрешает читать indeterminate value типа [unsigned] char в присваиваниях
где левая стророна это l-value типа [unsigned] char, но запрещает присваивать например int.
(При этом неясно, считается ли что паддинг может иметь indeterminate value)
#mysql #sql
Добрый день, можете подсказать как мне отсортировать выдачу MySQL по количеству совпадений?
К примеру есть запрос
SELECT * FROM `content` WHERE `text` LIKE "%hi%" AND `text` LIKE "%bro%"
Надо сделать так, что бы выдача была по убыванию ( то бишь там где больше всего bro
и hi - самое первое, где меньше всего - самое последнее ). Заранее спасибо!
Ответы
Ответ 1 SELECT *,
(length(text) - length(replace(text,'hi','')) / 2) +
(length(text) - length(replace(text,'bro','')) / 3) AS OrderField
FROM content
WHERE text LIKE "%hi%" AND text LIKE "%bro%"
ORDER BY OrderField
#mysql #data_structures
Помогите пожалуйста разобраться в следующей ситуации:
Есть два вида API где хранятся истории сообщений, это Zopim и Chat2Desc(импортировать
в Postman) . Пока эти два но могут потом и другие появится.
И моя ДБ с таблицей users:
Table users
id , email, phone, ...
В Zopim пользователи идентифицируются через email, a в Chat2Desc через телефон. Для
меня эти два поля важны, какой бы чат не был и сколько бы их не было.
То есть если я получаю емайл либо телефон пользователя в сообщениях, то делаю запрос
в свою базу (table users) для идентифицирования своего пользователя.
Да и в принципе даже структура чатов не важна, я данные как нибудь да выберу.А вот
как их правильно сохранить , да так чтоб у меня была одна структура для всех .
И вот что я придумал:
Разъяснение:
Таблица chats (Данные для чата) :
client_id - указывает на id таблицы chat_clients
duration - длительность чата
system_type - хранит имя чата (Zopim, Chat2Desc, ... )
created_at - дата создания
Таблица chat_clients (сведений об пользователей которые были в чате):
assigned_data - те инициалы под которыми пользователи были в чате
is_agent - (0 | 1): 1 => мой пользователь, 0 => не мой
users_id - id пользователя. Содержит либо id из таблицы users либо пустой.
bean_module - неважно (сведение о моём пользователе)
unique_col - Тут будет либо email (из Zopim) либо телефон (из Chat2Desc, Либо
думаю хранить id таблицы users).Будет гарантировать уникальность значений.
Связка users_id + unique_col уникальна (UNIQUE KEY user_id_unique_col_UQ (user_id,unique_col))
Таблица chat_messages:
text - текст сообщения.
client_id - указывает на id таблицы chat_clients
chat_id - указывает на id таблицы chats
file_id - указывает на id таблицы chat_files
transport - значение будет для Chat2Desc (Viber, WhatsApp ,...), для Zopim ,чтоб
не пустовал , Zopim
Таблица chat_files Сведения о переданных файлах в чате.Aналогичных таблиц может быть
может нет для хранения дополнительной инфы.
Доп инфо: В дальнейшем собираюсь для каждого пользователя выводит
историю сообщений.
Вопрос:
Как создать гибкую схему таблиц для хранения сообщений из разных чатов ?
Заранее благодарю.
Ответы
Ответ 1 Любые проблемы по созданию БД нужно разбивать на две части:
Нужно выделить то, что уже есть. Выделить данность, реальность. То, что вы не можете
изменить. То есть, выделить структуру внешних данных.
Нужно выделить то, что вы хотите получить. Желаемый вид и форма.
У вас в структуре всё в одной куче. И материальное представление, и логический вид.
Вам нужно выделить отдельные структуры под хранения данных из каждой отдельной системы
чатов, которые вы поддерживаете. Так как структуры отличаются ключами привязки к пользователям,
это должны быть разные структуры. Нет, конечно, можно всё сделать в одной таблице,
но тут вы ничего не приобретёте, но очень проиграете в сложности структуры. Если
вам нужно делать уникальный ключ по двум колонкам, то вы что-то делаете не так.
Затем нужно выделить то, что вы хотите получить. Значить вам нужна какая-то таблица
связки чатов и пользователей, и таблицы связки чатов в основной таблице и чатов в
материальных таблицах. Если нужно хранить сообщения в каждом чате для быстрого доступа,
то лучше будет это сделать явно, в отдельной таблице, не связанной с материальным представлением.
Так сообщения будут храниться два раза, но вы не будете связаны материальным представлением
после импорта сообщений, и ваш код получения данных из БД будет много проще и надёжней.
В современном мире нет смысла пытаться оптимизировать число таблиц в БД: если у вас
их будет десять или сотня, само по себе это нисколько не повлияет на скорость работы
с БД. Другое дело что сложная для понимания структура БД будет отнимать ваше время
и на первоначальную разработку, и на дальнейшую поддержку. Если траты вашего времени
можно избежать, то это следует сделать.
Сама сложная структура БД может представлять и сложность при масштабировании. Например,
шардинг и уникальные индексы идут по разные стороны улицы: вы не можете использовать
шардинг одновременно с уникальными индексами. То же можно сказать про скорость вставки
записей: уникальные индексы ей не помогают.
#python #python_3x #нейронные_сети #numpy #keras
Пишу нейронную сеть для распознавания цифр, вылезла ошибка - не могу разобраться
как изменить размерность массива, код ниже
import numpy as np
from keras.utils import np_utils
from keras.models import model_from_json
from keras.preprocessing import image
import matplotlib.pyplot as plt
%matplotlib inline
json_file = open("fully_mesh_network.json", "r")
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
loaded_model.load_weights("fully_mesh_network.h5")
loaded_model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])
img_path = '2.png'
img = image.load_img(img_path, target_size=(28,28), grayscale=True)
x = image.img_to_array(img)
x = 255 - x
x/= 255
x = np.expand_dims(x, axis = 0)
prediction = loaded_model.predict(x)
prediction = np_utils.categorical_probas_to_classes(prediction)
print(prediction)
---------------------------------------------------------------------------
ValueError: Error when checking : expected dense_1_input to have 2 dimensions, but
got array with shape (1, 28, 28, 1)
Ответы
Ответ 1 Судя по ошибке ваша модель ожидает 2D массив на входе.
попробуйте так:
x = x.reshape(28, 28)
PS метод np_utils.categorical_probas_to_classes() - отсутствует в современных версиях
Keras. Вместо него можно попробовать использовать метод: keras.utils.to_categorical()
#javascript #html
Имеется HTML, имеется JavaScript, который создает элементы в HTML.
Также имеется куча фотографий, которые будут подгружаться в HTML.
Подскажите, как можно фотографии автоматически подгрузить, ибо их много? По крайне
мере их названия (путь к ним), чтобы вставить в src?
Нашел как в JavaScript подключить require('fs'), но нельзя ведь в HTML использовать
require.
Ответы
Ответ 1 Не совсем понятен контекст. На сколько я подозреваю, у вас только фронт-енд.
require и библиотека fs - это из Node.js.
Предположу, что ваши фото хранятся в папке img, рядом с index.html и вы имеете следующую
структуру проекта:
.
├── img
| ├── image1.png
| └── image2.png
├── script.js
└── index.html
В этом случае, вы можете использовать файлы изображений указав относительный (относительно
index.html) путь к ним. Например:
Но в этом случае вам нужно в вашем script.js заранее создать массив с путями ко всем
картинкам, чтобы потом в цикле их добавить на страницу. Как я понимаю, в этом и проблема.
Чтобы получить имена файлов всех изображений в папке, вам нужно создать сервер на
Node.js, потому что это будет работа с файловой системой. А тут уже вариантов реализаций
может быть много, но схема будет приблизительно такая:
Запускается Node.js сервер, который будет работать как процесс на вашем компьютере;
В браузере вы откроете страницу http://localhost, где будет отрисован ваш index.html
(сервер отправит этот файл в браузер);
Перед отдачей браузеру файла index.html вы можете его модифицировать, и поместить
в него заранее массив путей ко всем изображениям.
Это обширная тема, и я не могу тут описать все возможные варианты реализаций начиная
от установки Node на вашу систему, заканчивая использованием движков html шаблонов,
которые (если сказать коротко) расширяют возможности обычного html.
Вам следует найти информацию по созданию сервера на Node.js. Например тут:
https://learn.javascript.ru/ajax-nodejs
https://webref.ru/dev/first-node-app/http-server
А после этого, возможно, переформулировать ваш вопрос, и описать результат, который
вам нужен.
#алгоритм #математика #любой_язык
Есть двумерная пирамида из кирпичей. Вес 1го - 1 кг, давит равномерно на 2 под ним
по 0.5кг.
То есть, если на верхний давит +100 кг, тогда под ним на каждый будет (100+1)/2 кг
- на нижний давит пол веса каждого над ним.
1,0=.5 2,0=.75 2,1=1.5 3,0=.875 3,1=.2.125
Как вычислять давление на любой из них, указывая позицию, например, к4-2, к8-4 ...
к(рядСверху,номерСлева) - как функция с 2 параметрами, возвращающая вес?
Думал, pяд*.5 + (pяд-1)/2 или 1*(c+1) / 2*p + 1*c / 2*p, разные другие варианты,
но никак не могу подобрать точный. (желательно на java)
Ответы
Ответ 1 А почему не воспользоваться рекурсией? Значения веса, номер ряда и номер кирпича
в ряду вставляйте какие вам надо:
public static void main(String[] args) {
float weight = 1; //вес кирпча
int row = 5; //номер ряда начиная с 1 с верху
int num = 3; //номер кирпича слева (или с права, как больше нравится) с 1
System.out.println(pressueOnBrick(row, num, weight));
}
//давление на один кирпич
public static float pressueOnBrick(int row, int num, float weight) {
return pressue(row, num, weight) - weight; //давление оказываемое на один кирпич
= полное
//давление которое оказывает кирпич
минус вес кирпича
}
//полное давление оказываемое кирпичём (включая свой вес)
public static float pressue(int row, int num, float weight) {
//в ряду не может быть кирпичей с номером меньше 1 и больше чем номер ряда(число
кирпичей в ряду = номеру ряда)
if (num < 1 || num > row) {
return 0;
}
//давление которое оказывает кирпич равно сумме веса кирпича и половине веса
кирпичей которые давят на него
//слева и справа
return weight + (pressue(row - 1, num - 1, weight) + pressue(row - 1, num, weight)) / 2;
}
Валидация вводимых значений на вашей совести.
Ответ 2 #include
#include
int main()
{
unsigned ranks{};
std::cin >>ranks; // общее количество рядов
double weight{};
std::map loads;
unsigned k{1};
for (; k <= ranks; ++k) {
loads.insert(std::make_pair(k, weight));
weight = (weight + 1)/2;
}
std::cout << std::endl << "вводим нужный ряд: " << std::endl;
std::cin >> k;
std::cout << "нагрузка для кирпичей " << k << " - го ряда: " << loads[k];
return 0;
}
После обсуждения с goldstar_labs пришел к выводу переписать, поскольку первый вариант
верный для двух рядов и для крайных кирпичей
#include
#include
using std::vector;
using std::cin;
void setValue(const vector& p1, vector& p2)
{
size_t k = p2.size();
if (k <= 2) return;
for (size_t i = 1; i < k - 1; ++i)
p2[i] += (p1[i] + 1)/2;
}
int main()
{
unsigned ranks{}, k{};
cin >>ranks; // общее количество рядов
double w{};
vector< vector > weights;
for (unsigned n = 1; n <= ranks; ++n) {
vector v(n, w);
weights.emplace_back(v);
if (n > 2 )
setValue(weights[n - 2], weights[n - 1]);
w = (w + 1)/2;
}
std::cout << std::endl << "вводим нужный ряд: " << std::endl;
std::cin >> k;
k %= ranks + 1;
std::cout << "нагрузки для кирпичей " << k << " - го ряда:\n";
for (double d : weights[k - 1])
std::cout << d << ' ';
return 0;
}
Выводить, думаю вы сами сможете в желаемом формате