Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Как поделить двоичное натуральное на 10 фиксированным количеством сдвигов, сложений и вычитаний?

#любой_язык


Умножение на 10 можно представить в виде

x * 10 = x * 8 + x * 2 = (x << 3) + (x << 1)


А можно ли каким-то подобным способом (сдвигами, сложениями и вычитаниями) делить
на 10? (Вычитание 10 из x до посинения - не подходит.)
    


Ответы

Ответ 1



Деление беззнаковых целых 32 и 64 разрядных на 10 с возвратом частного и получением остатка. // http://www.hackersdelight.org/divcMore.pdf uint32_t divu10(uint32_t n, uint32_t *rem) { uint32_t q, r; q = (n >> 1) + (n >> 2); q = q + (q >> 4); q = q + (q >> 8); q = q + (q >> 16); q = q >> 3; // orig: r = n - q*10; r = n - ((q << 3) + (q << 1)); *rem = r > 9 ? r - 10 : r; // orig: return q + ((r + 6) >> 4); return q + (r > 9); } uint64_t divu64_10(uint64_t n, uint32_t *rem) { uint64_t q, r; q = (n >> 1) + (n >> 2); q = q + (q >> 4); q = q + (q >> 8); q = q + (q >> 16); q = q + (q >> 32); q = q >> 3; // orig: r = n - q*10; r = n - ((q << 3) + (q << 1)); *rem = r > 9 ? r - 10 : r; // orig: return q + ((r + 6) >> 4); return q + (r > 9); } Практически используется для вывода uint64_t на 32-bit микропроцессоре, в котором нет 64-разрядного умножения.

Ответ 2



Давайте посмотрим, как оптимизируют деление на 10 популярные компиляторы. Например, для вот такой функции: int divide10(int32_t num) { return num / 10; } MSVC производит такой код: mov eax, 1717986919 ; 66666667H imul ecx sar edx, 2 mov eax, edx shr eax, 31 add eax, edx Переведём его на нормальный язык. Первые 3 строчки означают умножение числа на 0x66666667 = (2^34 + 6)/10 (тут ^ означает степень). Старшие 32 бита результата (edx) мы затем сдвигаем ещё на 2 бита вправо, итого выходит (x * 0x66666667) >> 34. Команда shr eax, 31 — сдвиг на 31 бит, получает знаковый бит результата. Он прибавляется к самому результату. То есть, для отрицательных чисел прибавляется 1. Итого int r = (int)((x * 0x66666667L) >> 34); r += (r < 0); GCC, Clang и Intel Compiler производят аналогичный код, только они делают знаковое расширение вместо беззнакового. Разбор математического обоснования такой замены проводится здесь. Вот краткая выжимка: Для делимого n >= 0 можно представить n в виде 10 * q + r, где q — искомый результат, а r — остаток. Получаем (x * 0x66666667L) >> 34 == [(10 * q + r) * (0x66666667L) / 2^34] (^ означает возведение в степень, [] — целую часть от деления). Наш числитель: (2^34 + 6)/10 * (10 * q + r) = q * 2^34 + 6 * q + 0x66666667L * r При делении на 2^34 первое слагаемое делится нацело и даёт искомое q, так что нужно убедиться, что остальное даёт 0. Это так, поскольку q < [2^31/10], а r <= 9, так что 6 * q + 0x66666667L * r < 6 * 214748364 + 0x66666667L * 9 == 15676630635 < 2^34 Для отрицательных n аналогично доказывается, что «хвост» нашего выражения даёт нулевой вклад, но т. к. при делении отрицательных чисел процессор должен делать округление в сторону нуля, приходится добавлять компенсирующую единицу. Как именно получать такое представление, лучше справится в книжках. Но мораль этого такова: подобные мелкие оптимизации компиляторы делают куда лучше нас. Поэтому не нужно пытаться «помочь» компилятору, он, поверьте, делает это (мелкие оптимизации кода) куда лучше нас с вами. Эпоха ручных оптимизаций прошла. Оптимизируйте алгоритмы. Дополнительное чтение по теме: Matt Godbolt: Что мой компилятор сделал для меня?

не работает onClick на теге <a>

#javascript #html

Обобщённый ребус VOLVO+FIAT=MOTOR

#любой_язык


По следам вопроса Ребус: VOLVO+FIAT=MOTOR.


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


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


Ответы

Ответ 1



Гм. Когда-то давно писал под свои нужды, умеет немного больше, чем просто арифметика - например, VOLVO+FIAT=MOTOR**Q! (в смысле - факториал, возведение в степень, квадратный корень... да даже системы уравнений :) - типа a+b=c; 2*a+3*b=8 в командной строке. Понимает русские буквы. Сносить два этажа и резать, гм... ну, вы поняли, как в анекдоте - не буду :) Многопоточность. Использовал немного модифицированный YACC, так что теперь не знаю, что и давать: YACC'овский файл или С++ :) Держите C++. Чистить лень :( #define _CRT_SECURE_NO_WARNINGS #define NDEBUG #include #include #include #include #include #include #include #include #include #include using namespace std; inline long long ipow(long long x, long long p) { if (x == 0 || x == 1) return x; long long r = 1; while(p) { if (p&0x1) r*= x; x *= x; p >>= 1; } return r; } inline unsigned long long isqrt(unsigned long long x) { unsigned long long x1, g0, g1; if (x <= 1) return x; int s = 1; x1 = x - 1; if (x1 > 0xFFFFFFFF) { s = s + 16; x1 >>= 32; } if (x1 > 0xFFFF) { s = s + 8; x1 >>= 16; } if (x1 > 0xFF) { s = s + 4; x1 >>= 8; } if (x1 > 0xF) { s = s + 2; x1 >>= 4; } if (x1 > 0x3) { s = s + 1; } g0 = 1ll << s; g1 = (g0 +(x>>s)) >> 1; while( g1 < g0) { g0 = g1; g1 = (g0 + (x/g0)) >> 1; } return g0; } long long fact(long long x) { assert(x <= 20); static long long vals[21] = {1,1,2,6,24,120,720,5040,0,0,0,0,0,0,0,0,0,0,0,0,0}; if (vals[x]) return vals[x]; long long s = 1; for(int i = 1; i <= x; ++i) { s *= i; vals[i] = s; } return s; } long long bifact(long long x) { assert(x <= 32); static long long vals[33] = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; if (vals[x]) return vals[x]; long long s = 1; for(int i = 1; i <= 31; i += 2) { s *= i; vals[i] = s; } s = 1; for(int i = 2; i <= 32; i += 2) { s *= i; vals[i] = s; } return vals[x]; } typedef long long ALM_STYPE; static int alm_parse( void * alm_param ); #define Number 257 #define Wrong 258 #define uminus 259 #define alm_IntError #define alm_clearin alm_char = -1 #define alm_errok alm_errflag = 0 #ifndef ALM_MAXDEPTH #define ALM_MAXDEPTH 150 #endif #define ALM_ERRCODE 256 template< typename RandomAccess, typename Compare > bool next_kpermutation( RandomAccess first, RandomAccess last, typename std::iterator_traits< RandomAccess >::difference_type k, Compare comp ) { typedef typename std::iterator_traits< RandomAccess >::difference_type Int; typedef typename std::iterator_traits< RandomAccess >::value_type Val; if( first == last ) return false; Int n = std::distance(first, last); if (k > n) return false; //Int n = distance(first, last); //Int i = -1; RandomAccess i = last; for(RandomAccess j = first + k - 1; j >= first; --j) { if (std::max_element(j,last) != j) { i = j; break; } } if (i == last) return false; { // Сначала ищем первый, больший p_[i] RandomAccess j = i; ++j; while(!comp(*i,*j)) ++j; RandomAccess imin = j; // Индекс минимального for(; j != last; ++j) { if (comp(*i,*j) && comp(*j,*imin)) { imin = j; } } std::swap( *i, *imin ); ++i; } RandomAccess u = first + std::min(k,n-1); while ( i < u ) { RandomAccess imin = i; for(RandomAccess j = i + 1; j != last; ++j) { if (comp(*j,*imin)) imin = j; } std::swap( *i, *imin ); ++i; } return true; } template< typename RandomAccess > bool next_kpermutation( RandomAccess first, RandomAccess last, int k ) { return ( next_kpermutation( first, last, k, std::less< typename std::iterator_traits< RandomAccess >::value_type >( ) ) ); } static void alm_error(int) {} static int alm_lex(void*qq,ALM_STYPE*alm_lval) { const char *& alm_textpointer = *(const char **)qq; while(*alm_textpointer==' ' /*||*alm_textpointer=='\t' */) ++alm_textpointer; switch(*alm_textpointer) { case 0: return EOF; case '0': { if (isdigit(*(alm_textpointer+1))) return Wrong; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { *alm_lval = 0; while(*alm_textpointer >= '0' && *alm_textpointer <= '9') { *alm_lval = (*alm_lval)*10 + (*alm_textpointer - '0'); ++alm_textpointer; } return Number; } break; case '*': if (*(alm_textpointer+1) == '*') { alm_textpointer += 2; return '^'; } case '+': case '-': case '(': case ')': case '/': case '=': case '^': case ';': case '!': case '#': case '%': { *alm_lval = 0; return *alm_textpointer++; } break; } ++alm_textpointer; return Wrong; } mutex mx; int total_count = 0; void almetis(int begin, int end, const char * buf, const char * symbols, int symno) { char digs[] = "0123456789"; int no = 0; do { if (no >= end) break; if (no < begin) continue; char stmt[2048]; const char * c = buf; char * t = stmt; for(;*c; ++c,++t) { switch(*c) { case ' ': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '(': case ')': case '+': case '-': case '*': case '/': case '=': case '^': case ';': case '!': case '#': case '%': case '\t': case '\r': case '\n': *t = *c; break; default: for(int j = 0; j < symno; ++j) { if (*c == symbols[j]) { *t = digs[j]; break; } } } } *t = 0; const char * q = stmt; if (alm_parse(&q) == 0) { lock_guard lk(mx); total_count++; printf("%s\n",stmt); } } while(++no, next_kpermutation(digs,digs+10,symno)); }; int main(int argc, char* argv[]) { setlocale(LC_ALL,"Rus"); int threads = thread::hardware_concurrency(); if (threads <= 1) threads = 1; else if (threads > 6) threads = 6; printf("Threads: %d\n",threads); char buf[2048] = { 0 }; for(int i = 1; i < argc; ++i) { strcat_s(buf,2048,argv[i]); if (i != argc-1) strcat_s(buf,2048," "); } char symbols[11] = { 0 }; int symno = 0; for(const char * c = buf; *c; ++c) { if (strchr(" 01234567890()+-*/=^;#%!\t\r\n",*c)) continue; bool found = false; for(int j = 0; j < symno; ++j) if (symbols[j] == *c) { found = true; break; } if (!found) symbols[symno++] = *c; if (symno == 11) { fprintf(stderr,"Too many symbols\n"); return 1; } } printf("There are %d symbols: %s\n",symno,symbols); int count = 1; for(int i = 0; i < symno; ++i) count *= (10-i); if ((count < 5000) || (threads == 1)) { almetis(0,count,buf,symbols,symno); } else { int part = count / threads; assert(threads * part == count); vector> fus; for(int i = 0; i < threads; ++i) { fus.push_back(async(almetis,i*part,(i+1)*part,buf,symbols,symno)); } for(auto& x: fus) x.get(); } printf("Solutions: %d\n",total_count); } static const int alm_exca[] ={ -1, 1, 0, -1, -2, 0, }; #define ALM_NPROD 22 #define ALM_LAST 228 static const int alm_act[]={ 9, 13, 4, 2, 9, 10, 1, 20, 8, 10, 7, 21, 8, 0, 7, 33, 17, 15, 20, 16, 20, 19, 21, 0, 21, 20, 0, 17, 15, 21, 16, 0, 19, 5, 17, 15, 20, 16, 0, 19, 21, 0, 0, 6, 0, 17, 14, 26, 0, 0, 19, 22, 23, 24, 25, 0, 0, 0, 27, 28, 29, 30, 31, 32, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 18, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 11, 12, 0, 0, 11, 12 }; static const int alm_pact[]={ -35, -1000, -1000, -1000, -58, -1000, -15, -31, -31, -31, -31, -1000, -1000, -31, -31, -31, -31, -31, -31, -31, -1000, -1000, -13, -13, -1000, -26, -1000, -8, 3, 3, -13, -13, -13, -1000 }; static const int alm_pgo[]={ 0, 6, 3, 2, 33, 43 }; static const int alm_r1[]={ 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; static const int alm_r2[]={ 0, 1, 1, 1, 2, 3, 1, 3, 1, 3, 3, 2, 2, 3, 3, 3, 2, 2, 2, 3, 1, 1 }; static const int alm_chk[]={ -1000, -1, -2, 256, -3, -4, -5, 45, 43, 35, 40, 257, 258, 59, 61, 43, 45, 42, 94, 47, 33, 37, -5, -5, -5, -5, -4, -5, -5, -5, -5, -5, -5, 41 }; static const int alm_def[]={ 0, -2, 1, 2, 3, 6, 8, 0, 0, 0, 0, 20, 21, 4, 0, 0, 0, 0, 0, 0, 16, 17, 11, 12, 18, 0, 5, 7, 9, 10, 13, 14, 15, 19 }; #define YACC_MEM_STACK //#define alm_IntError #ifdef alm_IntError #define alm_errNoMemory -1 #define alm_errStackOvr -2 #define alm_errSyntax -3 #else #define alm_errNoMemory "not enough memory" #define alm_errStackOvr "internal stack overflow" #define alm_errSyntax "syntax error" #endif #define ALM_FLAG (-1000) #define ALM_ERROR goto alm_errlab #define ALM_ACCEPT return(0) #define ALM_ABORT return(1) #if defined(YACC_MEM_HEAP) template class alm__memory { T * ptr_; public: alm__memory(unsigned int size) { ptr_ = new T[size]; }; ~alm__memory() { delete[] ptr_; }; T* ptr() { return ptr_; }; }; #endif static int alm_parse( void * alm_param ) { ALM_STYPE alm_lval = ALM_STYPE(), alm_val = ALM_STYPE(); int alm_char = -1; int alm_nerrs = 0; int alm_errflag = 0; #if defined(YACC_MEM_HEAP) int * alm_s; ALM_STYPE * alm_v; #endif #if defined(YACC_MEM_STACK) int alm_s[ALM_MAXDEPTH+2]; ALM_STYPE alm_v[ALM_MAXDEPTH+2]; #endif int alm_j, alm_m; ALM_STYPE * alm_pvt; int alm_state, *alm_ps, alm_n; ALM_STYPE * alm_pv; const int * alm_xi; #if defined(YACC_MEM_HEAP) alm__memory ALM__M (ALM_MAXDEPTH+2); alm__memory ALM__M1(ALM_MAXDEPTH+2); alm_v = ALM__M.ptr(); alm_s = ALM__M1.ptr(); if ((alm_v == NULL) || (alm_s == NULL)) { alm_error(alm_errNoMemory); return(1); }; #endif alm_state = 0; alm_char = -1; alm_nerrs = 0; alm_errflag = 0; alm_ps = &alm_s[-1]; alm_pv = &alm_v[-1]; alm_stack: if( ++alm_ps > &alm_s[ALM_MAXDEPTH] ) { alm_error(alm_errStackOvr); return(1); } *alm_ps = alm_state; ++alm_pv; *alm_pv = alm_val; alm_newstate: alm_n = alm_pact[alm_state]; if( alm_n <= ALM_FLAG ) goto alm_default; if( alm_char < 0 ) if( (alm_char = (int )alm_lex(alm_param,&alm_lval)) < 0 ) alm_char = 0; if( (alm_n += alm_char) < 0 || alm_n >= ALM_LAST ) goto alm_default; if( alm_chk[alm_n = alm_act[alm_n]] == alm_char ) { alm_char = -1; alm_val = alm_lval; alm_state = alm_n; if( alm_errflag > 0 ) --alm_errflag; goto alm_stack; } alm_default: if( (alm_n = alm_def[alm_state]) == -2 ) { if( alm_char < 0 ) if( (alm_char = (int )alm_lex(alm_param,&alm_lval)) < 0 ) alm_char = 0; for(alm_xi=alm_exca; (*alm_xi!=(-1)) || (alm_xi[1]!=alm_state);alm_xi+=2) ; while( *(alm_xi += 2) >= 0 ) if( *alm_xi == alm_char ) break; if( (alm_n = alm_xi[1]) < 0 ) return(0); } if( alm_n == 0 ) { switch( alm_errflag ) { case 0: alm_error(alm_errSyntax); alm_errlab: ++alm_nerrs; case 1: case 2: alm_errflag = 3; while ( alm_ps >= alm_s ) { alm_n = alm_pact[*alm_ps] + ALM_ERRCODE; if( alm_n >= 0 && alm_n < ALM_LAST && alm_chk[alm_act[alm_n]] == ALM_ERRCODE ) { alm_state = alm_act[alm_n]; goto alm_stack; } alm_n = alm_pact[*alm_ps]; --alm_ps; --alm_pv; } alm_abort: return(1); case 3: if( alm_char == 0 ) goto alm_abort; alm_char = -1; goto alm_newstate; } } alm_ps -= alm_r2[alm_n]; alm_pvt = alm_pv; alm_pv -= alm_r2[alm_n]; alm_val = alm_pv[1]; alm_m = alm_n; alm_n = alm_r1[alm_n]; alm_j = alm_pgo[alm_n] + *alm_ps + 1; if( alm_j >= ALM_LAST || alm_chk[alm_state = alm_act[alm_j]] != -alm_n ) alm_state = alm_act[alm_pgo[alm_n]]; switch(alm_m) { case 1:{ return alm_pvt[-0] ? 0 : -1; } break; case 2:{ return -1; } break; case 3:{ alm_val = alm_pvt[-0]; } break; case 4:{ alm_val = alm_pvt[-1]; } break; case 5:{ if (alm_pvt[-0] == 0) return -1; alm_val = alm_pvt[-2] && alm_pvt[-0]; } break; case 6:{ if (alm_pvt[-0] == 0) return -1; alm_val = alm_pvt[-0]; } break; case 7:{ alm_val = (alm_pvt[-2] == alm_pvt[-0]) ? 1 : 0; } break; case 8:{ alm_val = (alm_pvt[-0] == 0) ? 1 : 0; } break; case 9:{ alm_val = alm_pvt[-2] + alm_pvt[-0]; } break; case 10:{ alm_val = alm_pvt[-2] - alm_pvt[-0]; } break; case 11:{ alm_val = -alm_pvt[-0]; } break; case 12:{ alm_val = alm_pvt[-0]; } break; case 13:{ alm_val = alm_pvt[-2] * alm_pvt[-0]; } break; case 14:{ if (alm_pvt[-0] < 0) return -1; alm_val = 1; for(int i = 0; i < alm_pvt[-0]; ++i) alm_val *= alm_pvt[-2]; } break; case 15:{ if (alm_pvt[-0] == 0) return -1; alm_val = alm_pvt[-2] / alm_pvt[-0]; if (alm_val*alm_pvt[-0] != alm_pvt[-2]) return -1; } break; case 16:{ if (alm_pvt[-1] < 0) return -1; if (alm_pvt[-1] >=20) return -1; alm_val = fact(alm_pvt[-1]); } break; case 17:{ if (alm_pvt[-1] < 0) return -1; if (alm_pvt[-1] >=33) return -1; alm_val = bifact(alm_pvt[-1]); } break; case 18:{ if (alm_pvt[-1] < 0) return -1; alm_val = isqrt(alm_pvt[-0]); if (alm_val*alm_val != alm_pvt[-0]) return -1; } break; case 19:{ alm_val = alm_pvt[-1]; } break; case 20:{ alm_val = alm_pvt[-0]; } break; case 21:{ return -1; } break; } goto alm_stack; } Монстр, претендующий скорее на универсальность, чем на красоту. Поэтому по сравнению со специализированными программами, понятно, будет тормознее... Тут - https://ideone.com/GHbA34 - переправленная для ввода из stdin версия. Кстати, почему-то работает на Ideone медленно, на моей машине исходное уравнение в 4 потока ковыряет примерно 0.25с (полное время работы программы).

Ответ 2



document.querySelector("form").addEventListener('submit', function (e) { e.preventDefault(); var aaa = document.getElementById("a").value; var bbb = document.getElementById("b").value; var ccc = document.getElementById("c").value; var all = (aaa + bbb + ccc).replace(/(.)(?=.*\1)/g, ""); var abc = (aaa.charAt(1) && aaa[0]) + (bbb.charAt(1) && bbb[0]) + (ccc.charAt(1) && ccc[0]); console.log(`${aaa} + ${bbb} = ${ccc}`); var code = `(function () { var ${all.split("")}; var used = 0; var _${aaa}, _${bbb}, _${ccc}; ` + all.split("").map(c=> `for (X=0; X<10; ++X) if (!(used & (1< x.replace("\n", "\n" + r + "\n"), ` ${[aaa,bbb,ccc].map(x => `_${x} = ${x.replace(/\w+/g, s=>"(".repeat(s.length)+s).replace(/\w/g, "$&)*10+").replace(/\*10\+(?!\w)/g, "")}`).join("\n")} if(_${aaa} + _${bbb} === _${ccc}) console.log(_${aaa} + " + " + _${bbb} + " = " + _${ccc}) ` ).replace(RegExp(`([${abc}@])=0`, "g"), "$1=1") + ` })()` //console.log(code); eval(code); }); .as-console-wrapper.as-console-wrapper { max-height: calc(100vh - 3em) }
+ =


Ответ 3



Вариант на F#: [] let main argv = let sum1 = "VOLVO" let sum2 = "FIAT" let res = "MOTOR" let wordToInt(word : string, map : Map) = word.ToCharArray() |> Array.map(fun ch -> map.[ch]) |> Array.reduce(fun n1 n2 -> n1 * 10 + n2) let checkSolution(map : Map) = let s1 = wordToInt(sum1, map) let s2 = wordToInt(sum2, map) let resInt = s1 + s2 let resNums = resInt.ToString().ToCharArray() |> Array.map(fun ch -> ch.ToString() |> int) if resNums.Length <> res.Length then List.empty else let pairs = res.ToCharArray() |> Array.mapi(fun i ch -> (resNums.[i], ch)) let existingCharsFailed = pairs |> Array.exists(fun (num, ch) -> if map.ContainsKey(ch) then map.[ch] <> num else false) if existingCharsFailed then List.empty else let newChars = pairs |> Array.where(fun (num, ch) -> not(map.ContainsKey(ch))) if newChars |> Array.exists(fun (num1, ch1) -> newChars |> Array.exists(fun (num2, ch2) -> ch1 = ch2 && num1 <> num2)) then List.empty else if newChars |> Array.exists(fun (num1, ch2) -> map |> Map.exists(fun ch2 num2 -> num1 = num2)) then List.empty else [(s1, s2)] let rec find(index : int, chs : char[], set : Set, map : Map) = if index < chs.Length then set |> Set.toList |> List.map(fun i -> find(index + 1, chs, set.Remove(i), map.Add(chs.[index], i))) |> List.reduce(fun sol1 sol2 -> sol1 @ sol2) else checkSolution(map) let summandChars = (sum1 + sum2).ToCharArray() |> Array.distinct let solutions = find(0, summandChars, set [0..9], Map.empty) for (s1, s2) in solutions |> List.sortBy(fun (s1, s2) -> s1) do printfn "%d+%d=%d" s1 s2 (s1 + s2) 0

Ответ 4



Вариант на C# на массивах без Dictionary, возможно не очень понятный, зато быстрый. Что бы перебрать все возможные перестановки используется цикл до общего их количества. Например, если у нас 6 символов, первый символ может быть любой (10 вариантов), для второго символа остается 9 вариантов, и т.д. Получается, количество перестановок равно: 10 * 9 * 8 * 7 * 6 * 5. Дальше цикл раскручивает число в перестановку. Массив num содержит цифры, которые остались для выбора. Он "обнуляется" каждый раз: for (int j = 0; j < 10; j++) num[j] = j; Как только мы выбрали очередную цифру, она удаляется с массива: for (int k = mapNum; k < depth; k++) Цифры выбираются как остатки от деления, сначала на 10, потом на 9 (так как остается только 9 цифр для выбора), и т.д. static void Main(string[] args) { string sum1 = "VOLVO"; string sum2 = "FIAT"; string res = "MOTOR"; char[] chars = (sum1 + sum2 + res).Distinct().ToArray(); if (chars.Length > 10) Console.WriteLine("No solutions"); else { int permutations = 1; for (int i = 11 - chars.Length; i <= 10; i++) permutations *= i; int[] map = new int[256]; int[] num = new int[10]; for (int i = 0; i < permutations; i++) { for (int j = 0; j < 10; j++) num[j] = j; int depth = 10; int index = i; for (int j = 0; j < chars.Length; j++) { int mapNum = index % depth; map[chars[j]] = num[mapNum]; index /= depth; depth--; for (int k = mapNum; k < depth; k++) num[k] = num[k + 1]; } int num1 = 0; for (int j = 0; j < sum1.Length; j++) num1 = num1 * 10 + map[sum1[j]]; int num2 = 0; for (int j = 0; j < sum2.Length; j++) num2 = num2 * 10 + map[sum2[j]]; int resn = 0; for (int j = 0; j < res.Length; j++) resn = resn * 10 + map[res[j]]; if (num1 + num2 == resn) Console.WriteLine($"{num1}+{num2}={resn}"); } } }

Ответ 5



find(...parse("VOLVO + FIAT == MOTOR")); function parse(expr) { var letters = [...new Set(expr.match(/\w/g))]; var words = [...new Set(expr.match(/\w+/g))]; var defs = words.map(w => `const ${w} = ` + [...w].map((l, i) => `${l} * ${Math.pow(10, w.length - i - 1)}`).join(" + ") ).join("\n"); var q1 = `function ([${letters.join(", ")}]) { ${defs} return ${expr}; }`; var quotedExpr = "`" + expr.replace(/\w+/g, w => "${" + w + "}") + "`"; var q2 = `function ([${letters.join(", ")}]) { ${defs} return ${quotedExpr}; }`; return new Function (`return [${q1}, ${q2}]`)(); } function find(pred, fn) { const digits = [0,1,2,3,4,5,6,7,8,9]; do { if (pred(digits)) console.log(fn(digits)); let i; for (i = 1; i < digits.length; i++) if (digits[i-1] < digits[i]) break; if (i == digits.length) break; let j; for (let k = 0; k

Ответ 6



Вариант на C#: void Main() { var word1 = "VOLVO"; var word2 = "FIAT"; var word3 = "MOTOR"; var letters = string.Concat(word1,word2,word3).Distinct(); var distinctLetters = letters.Count(); if( distinctLetters > 10) return; var minNum = (int)Math.Pow(10, distinctLetters-1); var maxNum = (int)Math.Pow(10, distinctLetters) - 1; for(var i = minNum; i < maxNum; i++) { var dict = MakeDict(letters, i); if(!IsEnabled(dict)) continue; if(!IsSuitable(word1, word2, word3, dict)) continue; dict.Dump(); } } // Define other methods and classes here bool IsSuitable(string word1, string word2, string word3, Dictionary dict) { int a1 = Convert(word1, dict); int a2 = Convert(word2, dict); int a3 = Convert(word3, dict); return a1 + a2 == a3; } int Convert(string word, Dictionary dict) { var j = word.Length; int result = 0; foreach (var element in word) { int pos = dict[element]; result += pos * (int)Math.Pow(10, j); j--; } return result; } bool IsEnabled(Dictionary data) { // Каждая цифра может быть закреплена только за одной буквой return data.Select(x => x.Value) .GroupBy(x => x) .Select(g => new { Name = g.Key, Count = g.Count() }) .All(x => x.Count == 1); } Dictionary MakeDict(IEnumerable source, int num) { var result = new Dictionary(); string a = num.ToString(); var i = 0; foreach (var element in source) { var curChar = int.Parse(a.Substring(i, 1)); result.Add(element, curChar); i++; } return result; } Уже после написания вижу, что можно сделано неоптимальнее и можно ещё разгонять во многих местах. Просто оставлю как базовую версию на c#, чтобы было от чего отталкиваться.

Убрать switch размером с гору Эверест

#c_sharp #net


В общем, есть switch длиной с Эверест, как бы вы избавились от него, кроме как записывать
это в Dictionary?

        switch (currencyLeft)
        {
            case "BTC":
                return 0.001m;
            case "BCH":
            case "ETH":
            case "FCT":
            case "NEO":
            case "UBTC":
            case "XEM":
            case "ZEC":
                return 0.01m;
            case "MCO":
            case "QTUM":
            case "REP":
            case "STX":
            case "VET":
                return 0.1m;
            case "ETC":
            case "DASH":
            case "LTC":
            case "XLM":
            case "XRP":
            case "XMR":
                return 0.5m;
            case "GAT":
                return 8m;
            case "BMC":
            case "DENT":
            case "DRG":
            case "ETN":
            case "FDX":
            case "FLIXX":
            case "FSN":
            case "GZE":
            case "IND":
            case "IXT":
            case "MTN":
            case "OAX":
            case "ONG":
            case "QASH":
            case "RKT":
            case "SAL":
            case "SER":
            case "SNIP":
            case "SPHTX":
            case "STAC":
            case "STORJ":
            case "STU":
            case "TPT":
            case "TRX":
            case "VZT":
                return 1m;
            default:
                throw new Exception("Unsupported symbol");
        }


UPD: сам switch и так находится в приватном методе, который возвращает decimal и
принимает string. Задача в том, чтобы этот код (логику, если так можно "это" назвать)
как-то упростить (уменьшить), если это возможно, но не словарем.
    


Ответы

Ответ 1



Хардкод значений и курсов в коде - это нехорошо. Положите все это в CSV / JSON / базу данных. Т.е. в любое хранилище, кроме кода. Поднимайте из хранилища по первому обращению и десериализуйте в Dictionary.

Ответ 2



В switch – данные. Данные, по возможности, отделяют от логики программы. Раз уж данных много, можно хранить их в файлах, в настройках программы или в базе. Вот подходящий ответКак хранить данные в программе?

Как SVG сконвертировать в JPG или PNG на C#?

#c_sharp #svg


Я генерирую SVG файлы на C#, необходимо используя C# отрендерить их в JPG или PNG.
Как это можно сделать?

Интересны любые варианты, но ответом приму только тот который будет работать на shared
хостинге, так как скрипт будет запускаться там. Хостинг ASP.NET MVC 5 - Smarterasp.
    


Ответы

Ответ 1



Библиотека SVG для C#. Работает так: SvgDocument svgDoc = SvgDocument.Open("myFile.svg"); System.Drawing.Bitmap bitmap = svgDoc.Draw(); bitmap.Save("outFile.jpg", ImageFormat.Jpeg); Брать надо пакет не из NuGet так как там древняя версия и много багов, а прямо горячую, придётся скачать с github и скомпилировать. Проект рабочий, поддерживается и развивается, но как оказалось присутствуют баги, которые разработчики постепенно убирают. Библиотека позволяет не только рендерить готовый SVG файл, но и создавать его используя свой API на лету.

Ответ 2



1. Способ с использованием Inkscape. Запускаем из командной строки такую команду inkscape.exe -z "pathToSVGFile.svg" --export-png="pathToResultFile.png" В данной ситуации inskape я прописал их в системные пути. Как оказалось Inkscape не все файлы которые работают в браузере может преобразовать. Для корректной работы потребовалось атрибут href у use заменить на xlink:href и прописать в головном теге svg xmlns:xlink="http://www.w3.org/1999/xlink". 2. Способ с использованием node.js модуля svgexport Устанавливаем модуль svgexport глобально npm install svgexport -g Запускаем команду из консоли svgexport "FileNameWithPath.svg" "ResultFileNameWithPath.png" png 100% Сила этого метода в том, что node.js svgexport использует браузерный движок phantom.js для рендера, который основан на WebKit модуле, а это означает что результат будет наиболее соответствовать отображению в браузерах с Chromium основой. Кроме того получится по максимуму использовать именно браузерный синтаксис. Минусом этого метода оказалось то, что в команде конвертации при обработке путей с русскими названиями происходит ошибка, поэтому необходимо все файлы класть в англоязычные директории. Более подробно можно почитать тут и тут. Добавлено: Прочитав issue на github понял что пути не работали скорее всего из-за наличия пробелов в пути.

Ответ 3



При наличии Internet Explorer 11 можно использовать COM-объекты MSHTML: using System; using System.Collections.Generic; using System.Drawing; using System.Text; using System.Runtime.InteropServices; using System.ComponentModel; //Reference: System.Drawing //Reference: Microsoft HTML Object Library namespace SVG { public class SvgConvert { public static void ToPng(string svgcontent, string outpath) { RECTL rcClient = new RECTL(); bool b = SystemParametersInfo(SPI_GETWORKAREA, 0, ref rcClient, 0); if (b == false) { rcClient.bottom = 480; rcClient.right = 640; } int width = (int)(rcClient.right - rcClient.left); int height = (int)(rcClient.bottom - rcClient.top); IntPtr screendc = GetDC(IntPtr.Zero); string svghtml = "" + svgcontent + ""; mshtml.HTMLDocument doc = null; mshtml.IHTMLDocument2 d2 = null; IOleObject pObj = null; IViewObject pView = null; try { doc = new mshtml.HTMLDocument(); //создание документа d2 = (mshtml.IHTMLDocument2)doc; int hr; //установка размера документа pObj = (IOleObject)d2; SIZEL sz = new SIZEL(); sz.x = (uint)MulDiv(width, HIMETRIC_INCH, GetDeviceCaps(screendc, LOGPIXELSX)); sz.y = (uint)MulDiv(height, HIMETRIC_INCH, GetDeviceCaps(screendc, LOGPIXELSY)); ; hr = pObj.SetExtent((int)System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT, ref sz); if (hr != 0) throw Marshal.GetExceptionForHR(hr); //запись SVG в документ d2.write(svghtml); d2.close(); //преобразование в Bitmap pView = (IViewObject)d2; Bitmap bmp = new Bitmap(width, height); Graphics g = Graphics.FromImage(bmp); using (g) { IntPtr hdc = g.GetHdc(); hr = pView.Draw((int)System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, hdc, ref rcClient, IntPtr.Zero, IntPtr.Zero, 0); if (hr != 0) throw Marshal.GetExceptionForHR(hr); g.ReleaseHdc(hdc); } //сохранение в PNG bmp.Save(outpath, System.Drawing.Imaging.ImageFormat.Png); } finally { //освобождение ресурсов if (d2 != null) Marshal.ReleaseComObject(d2); if (pObj != null) Marshal.ReleaseComObject(pObj); if (pView != null) Marshal.ReleaseComObject(pView); if (doc != null) Marshal.ReleaseComObject(doc); } } [DllImport("gdi32.dll")] static extern int GetDeviceCaps(IntPtr hdc, int nIndex); [DllImport("user32.dll")] static extern IntPtr GetDC(IntPtr hWnd); [DllImport("user32.dll")] static extern bool SystemParametersInfo(int nAction, int nParam, ref RECTL rc, int nUpdate); public static int MulDiv(int number, int numerator, int denominator) { return (int)(((long)number * numerator) / denominator); } const int LOGPIXELSX = 88; const int LOGPIXELSY = 90; const int HIMETRIC_INCH = 2540; const int SPI_GETWORKAREA = 48; } [ComImport()] [GuidAttribute("0000010d-0000-0000-C000-000000000046")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] public interface IViewObject { int Draw([MarshalAs(UnmanagedType.U4)] int dwDrawAspect, int lindex, IntPtr pvAspect, IntPtr ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, ref RECTL lprcBounds, IntPtr lprcWBounds, IntPtr pfnContinue, int dwContinue); int a(); int b(); int c(); int d(); int e(); } [ComImport()] [Guid("00000112-0000-0000-C000-000000000046")] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IOleObject { void f(); void g(); void SetHostNames(object szContainerApp, object szContainerObj); void Close(uint dwSaveOption); void SetMoniker(uint dwWhichMoniker, object pmk); void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk); void x(); void y(); void DoVerb(uint iVerb, uint lpmsg, object pActiveSite, uint lindex, uint hwndParent, uint lprcPosRect); void EnumVerbs(ref object ppEnumOleVerb); void Update(); void IsUpToDate(); void GetUserClassID(uint pClsid); void GetUserType(uint dwFormOfType, uint pszUserType); int SetExtent(uint dwDrawAspect, ref SIZEL psizel); void GetExtent(uint dwDrawAspect, uint psizel); void Advise(object pAdvSink, uint pdwConnection); void Unadvise(uint dwConnection); void EnumAdvise(ref object ppenumAdvise); void GetMiscStatus(uint dwAspect, uint pdwStatus); void SetColorScheme(object pLogpal); }; public struct RECTL { public uint left; public uint top; public uint right; public uint bottom; } public struct SIZEL { public uint x; public uint y; } } Использование: string svgcontent = ""; SvgConvert.ToPng(svgcontent,"c:\\test\\svgimage.png"); Источник: Using IE to Save SVGs as Bitmaps to Wherever

Найти общий объем загруженной информации приложением на c#

#c_sharp #winforms #сеть #трафик


Есть приложение winforms на c#. Иногда оно обращается с запросами к разным интернет
ресурсам, получает ответы. Можно ли как-то узнать, сколько Mb было скачано за одну
сессию работы с приложением. То есть мне нужно просто узнать объем траффика через мое
приложение. Спасибо
    


Ответы

Ответ 1



Можно использовать счетчики производительности .NET CLR Networking. Для этого необходимо включить в раздел configuration файла app.config следующий элемент: Счетчики позволяют получить количество байт, отправленных и полученных средствами классов .NET, для указанного процесса. Создадим вспомогательный класс: using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Threading; using System.Net; using System.Text; namespace WinformsTest { public class NetworkStats { const string CategoryName = ".NET CLR Networking 4.0.0.0";//В .NET 2.0-3.5 заменить на ".NET CLR Networking" static PerformanceCounter _sentcounter = null; static PerformanceCounter _recvcounter = null; public static long BytesSent { get { if (_sentcounter == null) throw new InvalidOperationException("Class not initialized"); return _sentcounter.RawValue; } } public static long BytesReceived { get { if (_recvcounter == null) throw new InvalidOperationException("Class not initialized"); return _recvcounter.RawValue; } } public static bool Initialize() { //устанавливаем культуру, чтобы иметь предсказуемое имя счетчика CultureInfo ci = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; try { var category = new PerformanceCounterCategory(CategoryName); //для активации счетчиков нужно отправить хотя бы один запрос, неважно успешный или нет try { WebClient cl = new WebClient(); string html = cl.DownloadString("http://example.com"); Debug.WriteLine(html.Length); } catch (Exception ex) { Debug.WriteLine(ex.Message); } //получаем имя процесса Process pr = Process.GetCurrentProcess(); string prname = ""; using (pr) { prname = (pr.ProcessName.ToLower()); } var instances = category.GetInstanceNames(); //находим экземпляр счетчика для процесса string instance = ""; foreach (string s in instances) { if (s.ToLower().Contains(prname)) instance = s; } if (instance == "") return false; //создаем счетчики _sentcounter = new PerformanceCounter(CategoryName, "Bytes Sent", instance, true); _recvcounter = new PerformanceCounter(CategoryName, "Bytes Received", instance, true); return true; } finally { //возвращаем исходную культуру Thread.CurrentThread.CurrentCulture = ci; Thread.CurrentThread.CurrentUICulture = ci; } } } } Пример использования: public partial class Form1 : Form { public Form1() { InitializeComponent(); if (NetworkStats.Initialize() == false) { MessageBox.Show("NetworkStats.Initialize failed"); return; } timer1.Enabled = true; } public string PerformRequest(string url) { WebClient cl = new WebClient(); string html = cl.DownloadString(url); return html; } private void button1_Click(object sender, EventArgs e) { string s = PerformRequest("http://yandex.ru"); MessageBox.Show(s.Substring(0,300)); } private void timer1_Tick(object sender, EventArgs e) { textBox1.Text = "Bytes sent: " + NetworkStats.BytesSent.ToString() + "; Bytes received: " + NetworkStats.BytesReceived.ToString(); } }

Как делать блоки такого вида?

#javascript #html #css #css3 #svg




Каким образом лучше всего делать блоки такого вида? 

Чтобы при масштабировании форма была адаптивна и текст не выходил за границы блока.
    


Ответы

Ответ 1



Решение SVG Решение адаптивно, работает во всех браузерах. Текст и знак параграфа находятся внутри блока SVG, поэтому никогда не нарушится их взаимное положение и текст не выйдет за пределы блока при любом изменении размеров окна браузера. Рамки и текст будут изменяться пропорционально. * { margin: 0; padding: 0; } .container { width: 100%; height: 100%; }
§ TYPOGRAPHY Lorem ipsum dolor sit, amet consectetur adipisicing adipisicing elit Phasellus tincidunt dignissim nibh
Второй вариант блока с тенью Для реализации тени под первый полигон добавляем второй полигон и смещаем его на 2px вправо и вниз: § TYPOGRAPHY Lorem ipsum dolor sit, amet consectetur adipisicing adipisicing elit Phasellus tincidunt dignissim nibh


Ответ 2



Решение на CSS: * { margin: 0; padding: 0; } .wrapper { position: relative; max-width: 250px; margin: 3rem; padding: 1rem; border: 1px solid gray; } .angle, .in, .in2, .in2::before { position: absolute; height: 30px; } .angle { overflow: hidden; width: 160px; top: -30px; left: -1px; } .in { top: 0; left: -10px; width: 150px; background-color: gray; transform: skew(25deg); } .in2 { top: 1px; left: 1px; width: 130px; background-color: white; } .in2::before { content: ""; position: absolute; right: -8.4px; width: 25px; background-color: white; transform: skew(25deg); } .text { max-width: 350px; word-spacing: 3px; }

Lorem

Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro necessitatibus deleniti perspiciatis excepturi quia facere? Porro necessitatibus deleniti perspiciatis excepturi quia facere?

Решение на SVG: * { margin: 0; padding: 0; } h2 { margin: 1rem 0.3rem 0 0.3rem; } p { font-size: 13px; padding: 0 0.3rem; } .container { width:100%; height:100%; }

Lorem

Lorem ipsum dolor sit, amet consectetur adipisicing elit.



Ответ 3



CSS и clip-path: .block, .block:before { clip-path: polygon(0 0, 50% 0, 70% 20%, 100% 20%, 100% 100%, 0 100%); z-index: -1; } .block { width: 200px; height: 200px; background-color: black; position: relative; } .block:before { content: ''; width: 198px; height: 198px; background: white; display: block; position: absolute; top: 1px; left: 1px; } .inner { padding: 50px 10px 10px; }
Lorem text


В чем разница между loop и while true?

#while #rust


В чем разница между loop и while true в rust?


  В документации написано что:

loop {}

  
  Интерпретируется по другому компилятором чем:

 while true {}

  
  Хотел бы понять в чем эта разница и на сколько плохо использовать не loop, а while true


версия вопроса на Английском от @aij
    


Ответы

Ответ 1



На такой вопрос был дан ответ в Reddit. Разница заключается в том, что в случае while true все переменные должны быть инициализированы до цикла, а в случае loop это не обязательно: Пример с loop let x; loop { x = 1; break; } println!("{}", x) этот код отлично работает, однако следующий let x; while true { x = 1; break; } println!("{}", x); покажет ошибку компиляции "use of possibly uninitialised variable" с указанием на x в println. Во втором случае компилятор не определяет, что тело цикла всегда выполнится хотя бы один раз. перевод ответа @telotortium

Ответ 2



Сейчас есть еще одно отличие - из loop можно вернуть значение: let x; let y = loop { x = 1; break 42;}; println!("x={} y={}", x, y); Returning from loops

Подсчет ссылок в C++

#cpp #память #counter


Как реализовать подсчет ссылок при создании собственного класса C++? 

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


Ответы

Ответ 1



Простейший вариант - примерно так (это набросок, не более того): class CountedPtr { ... Type1 p1; // Данные Type2 p2; // Данные .... int * cnt; // Счетчик В конструкторе - помимо прочего - cnt = new int(1); В копирующем конструкторе - cnt копируется и увеличивается на 1. Соответственно обрабатывается присваивание (проще всего его реализовать через идиому обмена с копией). В деструкторе - что-то типа if (--*cnt == 0) { delete ptr; delete cnt; } Для начала (и понимания азов) хватит?

Ответ 2



Все уже реализовано: используйте std::shared_ptr.

Ответ 3



Вот у Страуструпа есть подсчет ссылок при реализации класса String. // String.h #include #include #define DEBUG #ifndef DEFINE_STRING #define DEFINE_STRING class String { struct Srep { char* s; int n; int sz; Srep(int, const char*); ~Srep() { delete[] s; } Srep* GetOwnCopy(); void Assign(int, const char*); private: Srep(const Srep&); Srep& operator=(const Srep&); }; class Cref { public: inline Cref(String&, int); inline Cref(const Cref&); Cref(); inline operator char() const; inline void operator=(char); private: String& s; int i; }; public: class Range { }; inline String(); inline String(const char*); String(const String&); ~String(); String& operator=(const char*); String& operator=(const String&); inline void Check(int) const; inline char Read(int) const; inlinevoid Write(int, char); inline Cref operator[](int); inline char operator[](int) const; inline int Size() const; private: Srep* rep; }; inline String::String() : rep(new Srep(0, "") ) { #ifdef DEBUG std::cout << "inline String::String()" << std::endl; #endif } inline String::String(const char* p) : rep(new Srep(strlen(p), p) ) { #ifdef DEBUG std::cout << "inline String::String(const char* p)" << std::endl; #endif } inline void String::Check(int i) const { #ifdef DEBUG std::cout << "inline void String::Check(int i) const" << std::endl; #endif if (i < 0 || rep->sz <= i) throw Range(); } inline char String::Read(int i) const { #ifdef DEBUG std::cout << "inline char String::Read(int i) const" << std::endl; #endif return rep->s[i]; } inline void String::Write(int i, char c) { #ifdef DEBUG std::cout << "inline void String::Write(int i, char c)" << std::endl; #endif rep = rep->GetOwnCopy(); rep->s[i] = c; } inline String::Cref String::operator[](int i) { #ifdef DEBUG std::cout << "inline String::Cref String::operator[](int i)" << std::endl; #endif Check(i); return Cref(*this, i); } inline char String::operator[](int i) const { #ifdef DEBUG std::cout << "inline char String::operator[](int i) const" << std::endl; #endif Check(i); return rep->s[i]; } inline int String::Size() const { #ifdef DEBUG std::cout << "inline int String::Size() const" << std::endl; #endif return rep->sz; } inline String::Cref::Cref(String& ss, int ii) : s(ss), i(ii) { #ifdef DEBUG std::cout << "inline String::Cref::Cref(String& ss, int ii)" << std::endl; #endif } inline String::Cref::Cref(const Cref& r) : s(r.s), i(r.i) { #ifdef DEBUG std::cout << "inline String::Cref::Cref(const Cref& r)" << std::endl; #endif } inline String::Cref::operator char() const { #ifdef DEBUG std::cout << "inline String::Cref::operator char() const" << std::endl; #endif s.Check(i); return s.Read(i); } inline void String::Cref::operator=(char c) { #ifdef DEBUG std::cout << "inline void String::Cref::operator=(char c)" << std::endl; #endif s.Write(i, c); } #endif // String.cpp #include "String.h" String::String(const String& r) { #ifdef DEBUG std::cout << "String::String(const String& r)" << std::endl; #endif r.rep->n++; rep = r.rep; } String::~String() { #ifdef DEBUG std::cout << "String::~String()" << std::endl; #endif if (--rep->n == 0) delete rep; } String& String::operator=(const char* p) { #ifdef DEBUG std::cout << "String& String::operator=(const char* p)" << std::endl; #endif if (rep->n == 1) rep->Assign(strlen(p), p); else { rep->n--; rep = new Srep(strlen(p), p); } return *this; } String& String::operator=(const String& r) { #ifdef DEBUG std::cout << "String& String::operator=(const String& r)" << std::endl; #endif r.rep->n++; if (--rep->n == 0) delete rep; rep = r.rep; return *this; } String::Srep::Srep(int nsz, const char* p) { #ifdef DEBUG std::cout << "String::Srep::Srep(int nsz, const char* p)" << std::endl; #endif n = 1; sz = nsz; s = new char[sz + 1]; strcpy(s, p); } String::Srep* String::Srep::GetOwnCopy() { #ifdef DEBUG std::cout << "String::Srep* String::Srep::GetOwnCopy()" << std::endl; #endif if (n == 1) return this; n--; return new Srep(sz, s); } void String::Srep::Assign(int nsz, const char* p) { #ifdef DEBUG std::cout << "void String::Srep::Assign(int nsz, const char* p)" << std::endl; #endif if (nsz != sz) { delete[] s; sz = nsz; s = new char[sz + 1]; } strcpy(s, p); }

Ответ 4



Я тоже оставлю здесь пример своей псевдореализации умного указателя, так как вопрос все-таки больше связан как реализовать самостоятельно, а не воспользоваться готовыми классами(хотя лучше пользоваться стандартными классами). Это всего лишь учебный пример, потому что Когда-то я также интересовался, как устроены умные указатели. template class my_smart_ptr { private: int* count; T* obj; public: my_smart_ptr(T* v) : obj(v) , count(new int) { *count = 1; std::cout << "my_smart_ptr: increment counter" << std::endl; } ~my_smart_ptr() { --*count; std::cout << "my_smart_ptr: decrement counter" << std::endl; if (*count == 0) { delete obj; obj = nullptr; delete count; count = nullptr; std::cout << "my_smart_ptr deleted the object. The count equals 0" << std::endl; } } T* operator -> () { return obj; } my_smart_ptr(const my_smart_ptr& other) { count = other.count; obj = other.obj; ++*count; std::cout << "my_smart_ptr: increment counter" << std::endl; } my_smart_ptr operator = (const my_smart_ptr& other) { my_smart_ptr t(other); return t; } }; class example { private: int _a; public: example(int a) : _a(a) { std::cout << "example: Call Constructor example" << std::endl; } ~example() { std::cout << "example: Call Destructor example: a=" << _a << std::endl; } void setA(int a) { _a = a; } }; my_smart_ptr foo() { auto t = my_smart_ptr(new example(10)); int a = 10 + 5; a += 5; return t; } void foo2(my_smart_ptr ex) { ex->setA(5); } void foo3() { my_smart_ptr a = foo(); foo2(a); } int main() { foo3(); } Это примерная реализация умных указателей. Суть работы их следующая. Есть некий счетчик ссылок, который является указателем на int. Так как это указатель, при копировании умного указателя счетчик копируется по ссылке(а не по значению), поэтому является общим для всех объектов. Пример класса является непотокобезопасным. Стандартные умные указатели являются потокобезопасными.

Изменить цвет текста, если фоновое изображение не белое?

#html #css #css3


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

Возможно ли каким-либо образом изменить цвет текста на основе фонового изображения
с помощью JQuery и / или CSS?    

Я должен сделать отзывчивый веб-сайт с этими требованиями, но застрял.  


    


Ответы

Ответ 1



Можно использовать режим смешивания. Поддержка браузерами такая же. Не применяется к body. body{ margin:0; font-size:50px; font-weight:bold; color:#4cb29c; } div{ background:linear-gradient(to right, #4cb29c 50%,transparent 50%); min-height:50vh; } p{ text-align:center; mix-blend-mode: difference; margin:0; } .circle{ color:#ee82ee; background: radial-gradient(circle at 75% 0px, #fff 35%, rgba(27, 128, 0, 0.6) 35.5%), url(https://picsum.photos/500/800?image=1069) center/cover; }

asdas das safd gfs gsfgsdf sdf sdfs df

asdas das safd gfs gsfgsdf sdf sdfs df



Ответ 2



Идея состоит в том, чтобы покрасить текст инвертированным фоном. Вот идея, использующая радиальный градиент: .box { padding: 50px; background: radial-gradient(circle at 70% 0px, #fff 45%, purple 45.5%) fixed; } p { font-size: 25px; font-weight: bold; /*Должен быть тот же фон, но инвертированный цвет*/ background: radial-gradient(circle at 70% 0px, purple 45%, #fff 45.5%) fixed; background-clip: text; color: transparent; -webkit-background-clip: text; -webkit-text-fill-color: transparent; }

Some text here Some text here Some text here Some text here

В вашем случае фон выглядит изображением, поэтому вам просто нужно найти похожий градиент, где вы можете инвертировать цвета. Другая идея - использовать базовое изображение и добавить наложение для создания результата: .box { padding: 50px; background: radial-gradient(circle at 70% 0px, #fff 35%, rgba(27, 128, 0, 0.6) 35.5%), url(https://picsum.photos/500/800?image=1069) center/cover; background-attachment:fixed; } p { font-size: 25px; font-weight: bold; /*Должен быть тот же фон, но инвертированный цвет*/ background: radial-gradient(circle at 70% 0px, rgba(27, 128, 0, 1) 35%, #fff 35.5%) fixed; background-clip: text; color: transparent; -webkit-background-clip: text; -webkit-text-fill-color: transparent; }

Some text here Some text here Some text here Some text here

Источник ответа

SQL - выбрать из строки до последнего вхождения

#mysql #sql


Есть таблица Info, где храняться пути, например:


  /mnt/sd/DATA/LINUX/DATA_2/lin/ToR/Transit/Transit_ILE00-wwwwww1749.txt


или


  /mnt/ssd/DATA/LINUX/DATA_2/lin/ToR/Transit/1/2/Transit_ILE00-MSsdsdsdwww.txt


Как выбрать только до последнего вхождения '/', чтобы получилось:


  /mnt/sd/DATA/LINUX/DATA_2/lin/ToR/Transit/


и


  /mnt/ssd/DATA/LINUX/DATA_2/lin/ToR/Transit/1/2/


С REGEXP_REPLACE и SUBSTRING_INDEX у меня не получается.
    


Ответы

Ответ 1



SELECT LEFT(`field`, LENGTH(`field`) - INSTR(REVERSE(`field`),'/')) FROM `Info` UPDATE: Запрос был написан в предположении, что "до последнего вхождения" означает "невключительно". Но в примере последний слэш включён в ответ - значит: SELECT LEFT(`field`, LENGTH(`field`) - INSTR(REVERSE(`field`),'/') + 1) FROM `Info`

Ответ 2



Всё как и в обычном программировании: находим последний слэш и обрезаем до него. Для этого используем следующие функции: LOCATE(subset, str) – находит первую встречу подстроки в строке (документация). REVERSE(str) – переставляет символы строки в обратной последовательности (документация). Это нужно чтобы искать последний слэш в строке. LENGTH(str) – возвращает длину строки (документация). Это нужно потому, что мы получаем индекс последнего слэша с конца строки, а нам нужно от её начала. LEFT(str, len) – вырезает левую часть строки по заданной длине (документация). Получается такой код: SELECT LEFT(path_field , LENGTH(path_field) - LOCATE('/', REVERSE(path_field) + 1) FROM sometable

Ответ 3



SELECT reverse(substr(reverse('fieldName'), instr(reverse('fieldName'),'/'))) FROM 'tableName'

Как сделать сегмент пончика в HTML5, используя только CSS

#html #css #css3 #svg


Как сделать эту фигуру, используя только CSS 



То, что я пробовал:  



.button-up {
  border-top: 100px solid red;
  border-left: 50px solid transparent;
  border-right: 50px solid transparent;
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
  border-bottom: 35px solid transparent;
  width: 200px;
}


Ответы

Ответ 1



Вариант попроще: .block { width: 6rem; height: 6rem; border-radius: 50%; border: 4rem solid transparent; border-top-color: green; }


Ответ 2



Я бы использовал линейный / радиальный градиент следующим образом: .box { width:200px; height:200px; border-radius:50%; background: linear-gradient(-30deg, white 50%,transparent 0), linear-gradient(30deg, white 50%,transparent 0), radial-gradient(circle at center,transparent 31%,blue 30%,blue 100%, transparent 51%); }
И с border: .box { width:200px; height:200px; border-radius:50%; background: linear-gradient(to top,white 59%,transparent 0), linear-gradient(-30deg, white calc(50% - 4px),green calc(50% - 4px),green 50%,transparent 0), linear-gradient(30deg, white calc(50% - 4px),green calc(50% - 4px),green 50%,transparent 0), radial-gradient(circle at center,transparent calc(30% - 4px),green calc(30% - 4px),green 30%,blue 30%,blue calc(70% - 3px),green 0); }
Вы также можете рассмотреть решение с SVG, которое может быть проще: Вот еще одна идея с clip-path: .box { width:200px; height:200px; border-radius:50%; background: radial-gradient(circle at center,transparent 31%,blue 30%,blue 100%, transparent 51%); -webkit-clip-path: polygon(0 0, 50% 50%, 100% 0); clip-path: polygon(0 0, 50% 50%, 100% 0); }


Что значит запись вида const { name } = value?

#javascript #const


Увидел в описании использования одного из npm-пакетов запись  вида const { NAME }
= value. В JavaScript не профи, так что никак не могу понять/найти зачем эти скобки
вокруг имени переменной и чем тогда это отличается от обычного const NAME = value?
    


Ответы

Ответ 1



Это называется деструктуризация, используется для более короткой записи const {name} = value; // value = {name: ''} name; // '' // то же самое что и const name = value.name; Можно использовать в параметрах функции const foo = ({prop}) => {} foo({prop: 'prop'}); Для возвращения нескольких параметров из функции const foo = () => ({var1: 1, var2: 2}) const {var1, var2} = foo(); Важно: имена переменных должны совпадать с ключами в объекте const {name} = {prop: 1}; // name = undefined // но если очень хочется:) const {prop: name} = {prop: 1}; // name = 1 Так же работает с массивами const [a, b] = [1, 2, 3, 4]; // a = 1, b = 2 Вот как теперь можно обменять значения двух переменных let a = 1, b = 0; [a, b] = [b, a];

Когда ручной вызов GC.Collect() оправдан?

#c_sharp #net #сборщик_мусора


Часто нахожу в коде вызовы GC.Collect(), например при работе с графиков через GDI+.

В умных книжках пишут, что его никогда не нужно вызывать самому.

Собственно вопрос, а есть ли оправданные случаи, когда его нужно вызывать или это
признак плохого когда?
    


Ответы

Ответ 1



Обычно не нужно. Иногда имеет смысл это делать: После уничтожения большого количества объектов (например, закрытия формы с большим количеством элементов) Когда приложение имеет четко выраженные периоды активности и простоя. Если принудительно вызвать сборку мусора в период простоя, уменьшится вероятность того, что она произойдет в период активности и затормозит выполнение кода. Ссылки: When to call GC.Collect() When is it acceptable to call GC.Collect?

Ответ 2



Просто так, без веских причин, и без точного понимания, что происходит при сборке мусора, дергать GC.Collect не стоит. Рантайм сам вполне справляется с автоматической сборкой мусора. Не стоит дергать Collect ни по таймеру, ни "на всякий случай" - это не даст никакого реального "ускорения" или улучшения. Более-менее реальные причины для вызова Collect: Вы точно знаете что в вашем приложении только что стало мусором огромное количество объектов И при этом мгновенно сократить потребление памяти приложением достаточно критично. Если мгновенность не требуется (а она не требуется почти никогда) - хватит автосборки. В рамках теста, который меряет потребление памяти. В рамках теста, который проверяет работу кода с WeakReference. При входе / выходе из режима GCLatencyMode.LowLatency и GCLatencyMode.SustainedLowLatency - стоит вызвать GC.Collect(2, GCCollectionMode.Forced) (возможно) при выходе из региона GC.TryStartNoGCRegion / GC.EndNoGCRegion. Топик на enSO: When is it acceptable to call GC.Collect?

starmap быстрее операции в цикле?

#python #modules


Вот код, решающий задачу отсюда:

def maximizingXor(l, r):
    return max([i^j for i in range(l, r+1) for j in range(i, r+1)])


А вот мое, не такое изящное решение с использованием модулей:

from itertools import combinations, starmap
from operator import xor

# Complete the maximizingXor function below.
def maximizingXor(l, r):
    return max(starmap(xor, combinations(range(l,r+1),2)))


Оно не столь красиво, но оказалось быстрее на l=10, r=15:
%timeit дает 3.81 µs ± 156 ns  на моем решении и  8.67 µs ± 1.1 µs per loop for solution
without functions callingна решении без модулей.      

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

Меня смущает тот факт, что конкретно здесь "в лоб" используется как бы встроенная
операция i^j, что по идее должно было быть быстрее, чем делать то же, но с использыванием
функции - оператора XOR. А поди ж ты )     

P.S.: как выяснилось, моен решение оказалось немного "разумнее" прямолинейного и
считает меньше элементов.
Более честно было бы сравнивать с вариантом i+1 вместо i

def maximizingXor(l, r):
    return max([i^j for i in range(l, r+1) for j in range(i+1, r+1)])


однако улучшение оказалось не решающим, а именно %timeit дает 6.62 µs ± 83.4 ns 

P.P.S.:  Ну и для полноты картины - tuple просто добавим скобок:

def maximizingXor_t(l, r):
    return max(tuple(starmap(xor, combinations(range(l,r+1),2))))   


здесь %timeit дает 4.11 µs ± 77.2 ns. То есть генератор при засовывании в тупль -
замедляется ...
    


Ответы

Ответ 1



Меня смущает кое-что... А именно то, что результат combinations(range(l,r+1),2) и for i in range(l, r+1) for j in range(i, r+1) разный. А конкретнее, вариант с двойным range выдает больше элементов. Переписал алгоритм и запустил: from itertools import combinations l=10 r=15 print(list(combinations(range(l,r+1),2))) print([x for x in combinations(range(l,r+1),2)]) print([(i, j) for i in range(l, r+1) for j in range(i, r+1)]) Результат: [(10, 11), (10, 12), (10, 13), (10, 14), (10, 15), (11, 12), (11, 13), (11, 14), (11, 15), (12, 13), (12, 14), (12, 15), (13, 14), (13, 15), (14, 15)] [(10, 11), (10, 12), (10, 13), (10, 14), (10, 15), (11, 12), (11, 13), (11, 14), (11, 15), (12, 13), (12, 14), (12, 15), (13, 14), (13, 15), (14, 15)] [(10, 10), (10, 11), (10, 12), (10, 13), (10, 14), (10, 15), (11, 11), (11, 12), (11, 13), (11, 14), (11, 15), (12, 12), (12, 13), (12, 14), (12, 15), (13, 13), (13, 14), (13, 15), (14, 14), (14, 15), (15, 15)] Давайте сравним производительность combinations, combinations_with_replacement и вложенного цикла: from timeit import timeit NUMBER = 10000 elapsed = timeit("""\ list(combinations(range(l,r+1),2)) """, setup=""" from itertools import combinations l=10 r=15 """, number=NUMBER) print(elapsed) elapsed = timeit("""\ list(combinations_with_replacement(range(l,r+1),2)) """, setup=""" from itertools import combinations_with_replacement l=10 r=15 """, number=NUMBER) print(elapsed) elapsed = timeit("""\ [x for x in combinations(range(l,r+1),2)] """, setup=""" from itertools import combinations l=10 r=15 """, number=NUMBER) print(elapsed) elapsed = timeit("""\ [x for x in combinations_with_replacement(range(l,r+1),2)] """, setup=""" from itertools import combinations_with_replacement l=10 r=15 """, number=NUMBER) print(elapsed) elapsed = timeit("""\ [(i, j) for i in range(l, r+1) for j in range(i, r+1)] """, setup=""" l=10 r=15 """, number=NUMBER) print(elapsed) Результат: 0.015679950736771395 : list(combinations(range(l,r+1),2)) 0.019574358240705608 : [x for x in combinations(range(l,r+1),2)] 0.017971126274343937 : list(combinations_with_replacement(range(l,r+1),2)) 0.023044554609408532 : [x for x in combinations_with_replacement(range(l,r+1),2)] 0.04071618284619548 : [(i, j) for i in range(l, r+1) for j in range(i, r+1)] Как видно: combinations генерирует меньше элементов и быстрее combinations_with_replacement. combinations_with_replacement при таком же результате быстрее выполняется относительно генератора списка с вложенным циклами Код с генератором списка медленнее, чем такой же, но получаемый через вызов list: list(...) быстрее [x for x in ...]. Впрочем, тут пример не совсем подходящий -- в таких случаях в генераторе списка выполняются дополнительные действия, а не просто перекладывание значения.

Ответ 2



Я вот не отвечу на ваш вопрос, потому что, подозреваю, на него нет однозначного ответа. Но вот то, что встроенные функции не всегда эффективнее модулей - это сущая правда, даже тогда, когда при написании этих модулей не стояла задача оптимизировать встроенные функции. В частности, есть такая вещь в numpy как type coercion - приведение элементов списка при создании их него numpy array к одному типу, причем тип выбирается из типов элементов списка самый "неудобный" (то есть, например, если есть среди целочисленных элементов хотя бы один float, все элементы при создании массива приводятся к типу float). Я как-то ради эксперимента решил сравнить следующие варианты превращения списка целочисленных значений в строковые: import numpy as np lst=list(range(1000)) a=np.array(lst+[' '])[:-1] #1 b=(np.array(lst+[' ']).tolist())[:-1] #2 то же, что и №1, но приведенное к каноническому списку c=list(map(str, lst)) #3 d=[str(x) for x in lst] #4 print(b==c==d) #-> True # для чистоты эксперимента сравниваем результаты (все, # кроме №1,потому что №1 - это numpy array) А теперь самое интересное: import timeit import numpy as np vals=[] codes=['a=list(range(1000));a=np.array(a+[' '])[:-1]', 'a=list(range(1000));a=(np.array(a+[' ']).tolist())[:-1]', 'a=list(range(1000));a=list(map(str, a))', 'a=list(range(1000));a=[str(x) for x in a]'] for code in codes: if 'np' in code: setup='import numpy as np' else: setup='' t = timeit.Timer(code, setup=setup) elapsed = t.timeit(number=10000) vals.append(elapsed) И получаем интересную картину: То есть, numpy type coercion у меня в два раза (а без преобразования в список - в три) быстрее встроенной map.

Ответ 3



Скорее всего причина в быстрой реализации функции combinations() по сравнению с вложенными циклами: In [19]: items = list(range(1000)) In [20]: %timeit [(i, j) for i in items for j in items] 110 ms ± 5.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) In [21]: %timeit list(combinations(items, 2)) 43.9 ms ± 961 µs per loop (mean ± std. dev. of 7 runs, 10 loops each) In [22]: %timeit list(combinations_with_replacement(items, 2)) 46 ms ± 4.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

К вопросу о конструкторах в языке программирования Java [закрыт]

#java #классы #объекты #наследование #конструктор


        
             
                
                    
                        
                            Закрыт. Данный вопрос необходимо конкретизировать. Ответы
на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он был сосредоточен только на одной проблеме, отредактировав его.
                        
                        Закрыт 1 год назад.
                                                                                
           
                
        
Возник достаточно интересный вопрос, на который я пока не смог найти ответ, но уверен,
что здесь мне помогут. 

Все мы прекрасно знаем о том, что при создании экземпляра класса в памяти у нас осуществляется
вызов конструктора, после чего будет создан сам объект. Выполнение кода внутри конструктора
сопряжено с инициализацией полей нашего объекта (не статические поля) и вызовом одного
из родительских конструкторов (в том случае, если мы не вызываем другой конструктор
из того же класса при помощи ключевого слова this). Вот тут мы и подходим к сути вопроса.
Допустим, что у нас имеется какой-нибудь произвольный класс, который не наследуется
явным образом от какого бы то ни было существующего класса. Что это для нас означает
в плане наследования? Это означает то, что класс будет наследоваться напрямую от корневого
класса (пусть даже неявно), которым в языке программирования Java является класс Object.
Меня немного смущает тот факт, что в нашем произвольном классе мы можем описать конструктор
с любым количеством и типами входных параметров (их порядок в коде также может быть
каким угодно), в то время, как в самом классе Object имеется всего лишь один единственный
конструктор, который не принимает никаких параметров. 

Собственно сам вопрос. Происходит ли вообще обращение к конструктору класса Object?
Если да, то значит ли это, что всё время вызывается один и тот же конструктор, который
не принимает никаких параметров на вход? Или же на основании конструктора наследника
автоматически создаётся аналогичный по набору входных параметров конструктор, только
уже для класса Object? Да и вообще, правильно ли я понимаю, что при вызове конструктора
у класса Object уже не идёт вызов конструктора суперкласса, как это происходит со всеми
другими классами (по той простой причине, что класс Object является корневым классом
и является единственным классом в языке программирования Java, который не имеет предков,
как прямых, так и косвенных)?

Буду благодарен всем, кто поможет хоть как-то прояснить данную ситуацию! :)
    


Ответы

Ответ 1



Происходит ли вообще обращение к конструктору класса Object? Да, это прописано в спецификации Java (§8.8.7. Тело конструктора): If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation "super();", an invocation of the constructor of its direct superclass that takes no arguments. Если тело конструктора не начинается с явного вызова конструктора [this или super] и заданный конструктор не является частью первоначального класса Object, то тело конструктора неявно начинается с вызова конструктора суперкласса super(); — выполнения конструктора без аргументов непосредственного класса-предка Также в п. §8.8.9 указывается, что у каждого класса есть конструктор по умолчанию, даже если он не указан явно. Это означает, что такой код: class Test { } эквивалентен такому: class Test { Test() { super(); //вызов конструктора Object } } И конструктор класса, который наследуется от Object будет вызывать конструктор Object. ... правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса, как это происходит со всеми другими классами (по той простой причине, что класс Object является корневым классом и является единственным классом в языке программирования Java, который не имеет предков, как прямых, так и косвенных)? Правильно понимаете. Предков у Object нет, и конструкторы вызывать не у кого. Для него явно сделано исключение в спецификации. Пример Для ясности предлагаю рассмотреть что именно происходит на простом примере. Возьмем следующий код: public class Test { public static void main(String[] args) { new Test(); new Object(); } } Сохраним его в файл (Test.java) и скомпилируем. Затем посмотрим какой байт-код сгенерировал компилятор (декомпилировать класс можно с помощью команды javap -c Test.class): Compiled from "Test.java" public class Test { //У класса появился конструктор public Test(); Code: 0: aload_0 //Который вызывает Object."" (super()) 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public static void main(java.lang.String[]); Code: 0: new #2 // class Test 3: dup //При создании объекта прописывается вызов конструктора (test."") 4: invokespecial #3 // Method "":()V 7: pop 8: new #4 // class java/lang/Object 11: dup 12: invokespecial #1 // Method java/lang/Object."":()V 15: pop 16: return } По инструкциям видно, что: Компилятор явно определяет для класса: (1) конструктор по-умолчанию (2) вызов конструктора родителя. Конструкторы на данном этапе не что иное как обычные методы, которые вызываются через invokespecial и которым даны названия недопустимые в Java (""), чтобы они не пересекались с другими методами. Конструкторы (в том числе и Object) и специальные правила, относящиеся к ним, в основном существуют только на этапе компиляции. Компилятор их проверяет, обрабатывает и преобразовывает в явные инструкции вызова методов. Выполняет инструкции в байт-коде виртуальная машина Java. Именно она определяет что произойдет при вызове invokespecial Test."" и invokespecial Object."". Разработчики виртуальных машин имеют большую свободу интерпретации этих инструкций и применяют сложные алгоритмы оптимизации выполнения кода и выделения памяти.

Ответ 2



При создании объекта всегда вызывается конструктор суперкласса. Если в конструкторе вы явно не указываете какой конструктор супер класса будет вызван, то вызовется конструктор по умолчанию (без параметров), но имей те в виду если вы создали в суперклассе конструктор с параметрами, то вам придётся определить и конструктор без параметров явно т.к. он уже будет не виден. Т.е. определив конструктор с параметрами в суперклассе и не определив в нем конструктор без параметров вы не сможете в наследнике создать объект и не указать в его конструкторе super(params) т.к. получите ошибку: в суперклассе отсутствует конструктор по умолчанию. На счёт класса Object вы правильно понимаете конструирование любого класса заканчивается на конструкторе класса Object. Конструктор вызывается один и тот же. Параметры в вашем конструкторе нужны только вашему классу т.к. он (конструктор) инициализирует ваши переменные о которых суперкласс ничего не знает, соответственно и передавать ему их не надо. А вот если в суперклассе есть инициализируемые поля, то необходимо явно вызывать его конструктор с параметрами. Конструктора создаются один раз.

Ответ 3



Происходит ли вообще обращение к конструктору класса Object? Конечно происходит, поскольку в каждом классе есть конструктор, заданный явно или не явно. значит ли это, что всё время вызывается один и тот же конструктор, который не принимает никаких параметров на вход? Конструктор родительского класса вызывается независимо от того используете вы конструктор с параметрами или без. правильно ли я понимаю, что при вызове конструктора у класса Object уже не идёт вызов конструктора суперкласса Нет, неправильно. Сначала вызывается конструктор суперкласса, а потом конструктор подкласса. Если в классе есть конструктор, то он вызывается - если нет, то создаётся конструктор по умолчанию, который тоже вызывается, но вы этого не видите.

Определение типа захватываемой лямбдой переменной

#cpp #lambda #language_lawyer


#include 
#include 


int main() {
    int x, &y = x;
    [=] {
        std::cout << std::is_same_v
                  << std::is_same_v
                  << std::is_same_v;

        std::cout << std::is_same_v
                  << std::is_same_v
                  << std::is_same_v;
    }();
}


Компилятор gcc выводит 001010, а clang - 001001. Какой вариант правильный и почему?
    


Ответы

Ответ 1



Достаточно запутанный вопрос, но похоже что clang прав. Для начала рассмотрим, как определяется тип выражения e в decltype(e). dcl.type.decltype#1: For an expression e, the type denoted by decltype(e) is defined as follows: if e is an unparenthesized id-expression naming a structured binding, decltype(e) is the referenced type as given in the specification of the structured binding declaration; otherwise, if e is an unparenthesized id-expression naming a non-type template-parameter ([temp.param]), decltype(e) is the type of the template-parameter after performing any necessary type deduction ([dcl.spec.auto], [dcl.type.class.deduct]); otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed; otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e; otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; otherwise, decltype(e) is the type of e. x и y являются glvalue, но не являются xvalue, а значит являются lvalue в соответствии с basic.lval#fig:categories: Таким образом, срабатывает предпоследний пункт определения типа, то есть варианты с int отпадают сразу. Далее, рассмотрим следующую цитату. expr.prim.lambda.capture#11: Every id-expression within the compound-statement of a lambda-expression that is an odr-use of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use refers to the original entity, never to a member of the closure type. However, such an id-expression can still cause the implicit capture of the entity. — end note ] ... В данном случае выражения не являются потенциально вычисляемыми (т.к. являются операндами decltype), а значит соответствующие переменные не являются odr-использованными. Однако важно примечание - такие выражения всё ещё могут рассматриваться в контексте лямбда-замыканий, что подтверждается следующей цитатой. expr.prim.id.unqual#2: ... If the entity is a local entity and naming it from outside of an unevaluated operand within the declarative region where the unqualified-id appears would result in some intervening lambda-expression capturing it by copy ([expr.prim.lambda.capture]), the type of the expression is the type of a class member access expression ([expr.ref]) naming the non-static data member that would be declared for such a capture in the closure object of the innermost such intervening lambda-expression. [ Note: If that lambda-expression is not declared mutable, the type of such an identifier will typically be const qualified. — end note ] ... Другими словами, несмотря на то что захвата не происходит, тип выражения определяется так, как будто бы захват есть. Также в примечании сказано про константность идентификатора, если лямбда не имеет спецификатора mutable, что подтверждается следующим пунктом. expr.prim.labmda.closure#4: The function call operator or operator template is declared const ([class.mfct.non-static]) if and only if the lambda-expression's parameter-declaration-clause is not followed by mutable. ... Интересно, что из-за нечёткости формулировок и разбросанности их по разным разделам стандарта (на мой взгляд) оба компилятора имеют соответствующие багрепорты: gcc, clang. Однако в clang репорт закрыт как неверный (RESOLVED INVALID), а в gcc открыт до сих пор (UNCONFIRMED).

Ответ 2



При захвате по значению [=] переменные захватываются копированием. Для каждой захваченной сущности создаётся безымянный член данных внутри лямбда объекта. Для ссылок на объекты тип получается тоже ссылочный: The type of such a data member is the referenced type if the entity is a reference to an object, an lvalue reference to the referenced function type if the entity is a reference to a function, or the type of the corresponding captured entity otherwise. Так как уточнения о том, какой должна быть ссылка: const или не-const нет, оба рассмотренных компилятора дают подходящий под стандарт результат. Однако, известно, что для модификации, захваченных по значению сущностей нужно дополнительно помечать лямбду как mutable. И если это сделать, можно увидеть, что оба компилятора уже будут давать одинаковые результаты (clang, gcc): #include #include int main() { int x = 42, &y = x; [=]() mutable { std::cout << std::is_same_v << std::is_same_v << std::is_same_v; x = 0; y = 100500; }(); std::cout << "\n" << x << "\n"; } 010 42 Так как требуется явная модификация y = 100500, то тип y уже не может быть константной ссылкой и становится обычной ссылкой. Модифицируются же по-прежнему копии внутри лямбды.

Ответ 3



Ваш пример практически повторяет пример из C++17 стандарта языка. void f3() { float x, &r = x; [=] { // x and r are not captured (appearance in a decltype operand is not an odr-use) decltype(x) y1; // y1 has type float decltype((x)) y2 = y1; // y2 has type float const& because this lambda is not mutable and x is an lvalue decltype(r) r1 = y1; // r1 has type float& (transformation not considered) decltype((r)) r2 = y2; // r2 has type float const& }; } Форма decltype((x)) не является odr-use для x, т.е. она не вызывает неявного захвата x, но она должна вести себя так, как будто x было захвачено и decltype((x)) ссылается именно на захваченное x. При захвате ссылки по значению происходит захват по значению именно ссылаемого объекта. Таким образом никакой разницы в способах x и y захвата в вашем примере нет. Ваши захваченные x и y имеют тип int. Внутри тела не-mutable лямбды они видны как lvalues типа const int. Т.е. в контексте тела вашей лямбды и decltype((x)) и decltype((y)) дают тип const int &. Однако эта часть стандарта подвергается переработке для C++20. Возможно, что есть изменения.

Как узнать количество полей в структуре?

#cpp


Как узнать количество полей в структуре?

struct A {
  int a,b; // 2 поля
}

struct B {
  float a,b,c; // 3 поля
}

    


Ответы

Ответ 1



В общем случае это невозможно. В C++23 должны добавить рефлексию, с помощью которой это можно будет делать, но до тех пор придется довольствоваться разными сомнительными хаками. Есть несколько решений для частных случаев: Если у вас все поля в структуре одного типа, и вы знаете, какого именно, то, как предложил @ARHovsepyan, можно поделить размер структуры на размер одного ее члена: int main() { std::cout << sizeof(A) / sizeof(int) << '\n'; std::cout << sizeof(B) / sizeof(float) << '\n'; } Хотя, ЕМНИП, компиляторам разрешается добавлять в структуры сколько угодно неиспользуемых байт (padding) между и после полей, чтобы расположить их в памяти определенным образом (из-за чего этот трюк перестал бы работать), я еще не видел ни одного компилятора, который действительно делал бы это для структур с полями одного типа. Есть еще один вариант, более универсальный. Если вы не создали для вашей структуры ни одного конструктора, и в структуре нет полей-массивов, то можно сделать вот что: #include #include #include #include struct stub { template operator T() const; }; template using detect_brace_constructible = decltype(T{std::declval

()...}); template constexpr bool constructible_with_stubs(std::index_sequence) { return std::experimental::is_detected_v< detect_brace_constructible, T, std::enable_if_t<1 || I, stub>... >; } template constexpr int field_count_impl(std::index_sequence) { int ret = -1; ((void(ret = I), constructible_with_stubs(std::make_index_sequence{})) && ...); return ret-1; } template inline constexpr int field_count = field_count_impl(std::make_index_sequence{}); struct A { int a,b; }; struct B { float a,b,c; }; int main() { std::cout << field_count << '\n'; // 2 std::cout << field_count << '\n'; // 3 } Этот шаблон последовательно пробует конструировать структуру с возрастающим количеством аргументов: A{} A{stub{}} A{stub{}, stub{}} A{stub{}, stub{}, stub{}} ... Где stub{} - это заглушка, которая может быть преобразована в любой нужный тип. Такое конструирование будет успешно, пока заглушек столько же, сколько полей в структуре, или меньше. Если заглушек будет больше - будет ошибка. Мы эту ошибку обнаруживаем с помощью SFINAE и возвращаем число заглушек, при котором ошибки не было. Но если в структуре есть массив, то такой шаблон ошибочно посчитает каждый элемент массива за отдельное поле структуры.

Ответ 2



В добавление к существующему ответу: есть библиотека Precise and Flat Reflection, в которой реализован требуемый функционал. Там же можно посмотреть как всё сделано, если интересна реализация.