1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | for (i = 0; i < w; i++) { for (j = 0; j < h; j++) { BOOL b_is_boundary = FALSE; if (delta_w > delta_h) { if ( j == ( int )( (h*delta - (old_above_coordinate- \ old_below_coordinate))/(2*delta) ) || j == ( h-( int )( (h*delta - (old_above_coordinate- \ old_below_coordinate))/(2*delta) ) ) ) b_is_boundary = TRUE; } else { if ( i == ( int )( (w*delta - (old_right_coordinate- \ old_left_coordinate))/(2*delta) ) || i == ( w-( int )( (w*delta - (old_right_coordinate- \ old_left_coordinate))/(2*delta) ) ) ) b_is_boundary = TRUE; } double x0 = left_coordinate + delta * ( double )i; double y0 = above_coordinate - delta * ( double )j; double x = x0; double y = y0; int k = 0; #define MAX_ITERATION 1000 while (k < MAX_ITERATION) { double real_part = x*x-y*y+x0; double imaginary_part = 2*x*y+y0; double z_abs_square = real_part*real_part + imaginary_part*imaginary_part; if (z_abs_square > 4.0) { break ; } else { x = real_part; y = imaginary_part; } k++; } if (k < MAX_ITERATION) { //unsigned long colors[16] = unsigned long colors[50] = { RGB(0xDE , 0xB8 , 0x87), ... RGB(0x19 , 0x19 , 0x70 ) }; //SetPixel(hdc, i, j , colors[k%16]); SetPixel(hdc, i, j , colors[k%50]); if (b_is_boundary) SetPixel(hdc, i, j , RGB(255, 255, 255)); } else { SetPixel(hdc, i, j , RGB(0, 0, 0)); if (b_is_boundary) SetPixel(hdc, i, j , RGB(255, 255, 255)); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | if (!(w == 200 || w == 250 || w == 400 || w == 500 || w == 800 || w == 1000 /*|| w == 1024*/ ) || !(h == 200 || h == 250 || h == 400 || h == 500 || h == 800 || h == 1000 /*|| h == 1024*/ ) ) { AfxMessageBox(L "width and height not supported" ); return ; } char * one_w_strI = (w == 200) ? "0.005" : ( w == 250 ? "0.004" : ( w == 400 ? "0.0025" : ( w == 500 ? "0.002" : ( w == 800 ? "0.00125" : ( w == 1000 ? "0.001" : ( "error characters" ) ) ) ) ) ); char * one_h_strI = (h == 200) ? "0.005" : ( ... |
1 2 | #define DEFAULT_CLIENT_AREA_WIDTH 500//1000 #define DEFAULT_CLIENT_AREA_HEIGHT 250// 800 |
1 2 3 4 | fI fI_left_coord( "-2.25" ); fI fI_right_coord( "2.25" ); fI fI_above_coord( "2.0" ); fI fI_below_coord( "-2.0" ); |
1 2 3 4 5 6 7 8 | class float_number{ public : bool minus; char * number; //in absolute value form int point_pos; ... }; |
1 2 3 4 5 6 7 8 | class floatII{ public : bool minus; //with '-' sign? char * digits; //no '.' inside int point_pos_r; //counting from the right side ... }; |
1 2 | typedef float_number fI; typedef floatII fII; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | fI fI_left_coord ( "-2.25" ); fI fI_right_coord( "2.25" ); fI fI_above_coord( "2.0" ); fI fI_below_coord( "-2.0" ); fI delta_wI, delta_hI, deltaI; #if 1 fI w_factorI(one_w_strI); fI h_factorI(one_h_strI); delta_wI = (fI_right_coord - fI_left_coord ) * w_factorI; delta_hI = (fI_above_coord - fI_below_coord) * h_factorI; if (delta_wI > delta_hI) deltaI = delta_wI; else deltaI = delta_hI; #endif #if 1 fI x0I(fI_left_coord ); fI y0I(fI_above_coord); fI aI( "2" ); fI threshold( "4.0" ); #endif #if 1 for (i = 0; i < w; i++) { y0I = fI_above_coord; for (j = 0; j < h; j++) { fI xI( "0" ); fI yI( "0" ); int k = 0; #define MAX_ITERATION 10//20//100 while (k < MAX_ITERATION) { fI real_part = xI*xI-yI*yI+x0I; fI imaginary_part = aI*xI*yI +y0I; fI z_abs_square = real_part*real_part + imaginary_part*imaginary_part; if (z_abs_square > threshold) { break ; } else { xI = real_part; yI = imaginary_part; } k++; } if (k < MAX_ITERATION) { SetPixel(hdc, i, j , colors[k%50]); } else { SetPixel(hdc, i, j , RGB(0, 0, 0)); } y0I = y0I - deltaI; } x0I = x0I + deltaI; } #endif |
可见位于(0 0)这个点第1次迭代即退出了循环,在M集的外边。然后计算下一个点(0 1)。![]()
1 2 3 4 5 6 | #pragma comment(lib, "libmpfr.a") #pragma comment(lib, "libgmp.a") #pragma comment(lib, "libgcc.a") #pragma comment(lib, "libgcc_s.a") #pragma comment(lib, "libmingwex.a") #pragma comment(lib, "libmsvcrt.a") |
上图循环1次即结束了,log较短。再以坐标(22 125)的点的第k=9次迭代进一步看看,这下log长了,一张图显示不下,而且我这里只好把其中冗长的多行数字 用*行代替。下面第1张完成了实部精确值、近似值的比较:![]()
第2张完成了虚部精确值、近似值的比较。因该点在实轴上,虚部为0,所以log很短。![]()
最后第3张中完成了z的模方的精确值、近似值的比较。![]()
这些图中没标记的“[FRACTION ... / ...]”字样的部分是GMP采用的分数形式表示,即 分子 / 分母,且是不可约的。![]()
1 2 3 4 5 | extern floatII truncate_floatII( int x_precision, int y_precision, int delta_precision, int min_precision_to_truncate, floatII& f, int add_to_tail_precision, int * p_pos); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | floatII truncate_floatII( int x_precision, int y_precision, int delta_precision, int min_precision_to_truncate, floatII& f, int add_to_tail_precision, int * p_pos) { *p_pos = 0; int truncate_part_len = 0; int i; //if(f.point_pos_r < min_precision_to_truncate) // return f; floatII approximation = f; int max = x_precision ; max = y_precision > max ? y_precision : max ; max = delta_precision > max ? delta_precision : max ; if (f.point_pos_r <= max) return approximation; max += add_to_tail_precision; if (f.point_pos_r <= max) return approximation; else truncate_part_len = f.point_pos_r - max; max -= add_to_tail_precision; //go to NO.`max' after '.' of f /* result (= x * y) ((precison of a by b )) : (a) common case: (some non-'0' ahead) 0.02003004080509760000000001300xxxxxxxxxxxxxxxxx (b) rare case: (all '0's ahead) 0.000000000000000000000000013000000050000xxxxxxxx or 0.0000000000000000000000000130 (shorter vs. above) */ int len = strlen (f.digits); int int_len = len - f.point_pos_r; char * p = approximation.digits; bool is_there_nonzero = false ; for (i = 0; i < (int_len + max); i++) { if (p[i] != '0' ) { is_there_nonzero = true ; break ; } } if (is_there_nonzero) { approximation.point_pos_r -= truncate_part_len; int len2 = len - truncate_part_len; memset (&p[len2], 0, truncate_part_len); p[len2] = '\0' ; //clear again ( redundant though) *p_pos = len2 - int_len + 1; //*p_pos = &p[len2] - &p[int_len] + 1; return approximation; // (.) //531415 //0123456 // ^ } else //TODO: to log and check this rare/corner case. { for (i = (int_len + max); i < len; i++) { if (p[i] != '0' ) break ; } if (i == len) { floatII result( "0" ); return result; } else { if ( (len - i -1) <= add_to_tail_precision ) return approximation; else { truncate_part_len = len - (i + 1 + add_to_tail_precision); approximation.point_pos_r -= truncate_part_len; memset (&p[i+1+add_to_tail_precision], 0, truncate_part_len); *p_pos = i+1+add_to_tail_precision - int_len + 1; return approximation; } } } } |
其中GMP截断近似的实现:(以GMP_truncate_real()为例。GMP_truncate_imag()代码只是把"real"换成"imag"而已。)![]()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | void GMP_truncate_real( char * str_numerator, char * str_denominator, char * str_gmp_mpfr, int * p_exp, int mpfr_precision, int len, int trunc_pos) { mpz_t numerator; mpz_t denominator; mpq_t a; mpfr_t f1, f2; mpfr_exp_t exp ; mpz_init(numerator); mpz_init(denominator); mpq_init(a); mpq_set(gmp_real_approx, gmp_real); if (trunc_pos == 0) { //return; } else { int n; char * str; char * p; mpz_set(denominator, mpq_denref(gmp_real_approx)); //gmp_printf("denominator is %Zd\n", denominator); mpq_set_si(a, 10, 1); n = 0; while ( mpz_cmp_si(denominator, 1) != 0) { mpq_mul(gmp_real_approx, gmp_real_approx, a); //gmp_printf("%#040Qd\n", gmp_real_approx); mpz_set(denominator, mpq_denref(gmp_real_approx)); n++; } //printf("\n multiplied by 10^ %d\n" , n); mpz_set(numerator, mpq_numref(gmp_real_approx)); //gmp_printf("numerator is %Zd\n", numerator); str = ( char *) malloc (len+16); //some more space memset (str, 0, len+16); //buggy: memset(str, 0, sizeof(str)); mpz_get_str(str, 10, numerator); //printf("str got:%s\n", str); p = str + strlen (str); p -= (n-trunc_pos)+1; //53.1415926 while ( *p != '\0' ) *p++ = '0' ; mpq_set_str(gmp_real_approx, str, 10); mpq_canonicalize(gmp_real_approx); while (n > 0) { mpq_div(gmp_real_approx, gmp_real_approx, a); //gmp_printf("%#040Qd\n", approx); n--; } free (str); } mpz_set(numerator, mpq_numref(gmp_real_approx)); mpz_get_str(str_numerator, 10, numerator); mpz_set(denominator, mpq_denref(gmp_real_approx)); mpz_get_str(str_denominator, 10, denominator); //for visualizing the string mpfr_init2(f1, (mpfr_prec_t)mpfr_precision); mpfr_init2(f2, (mpfr_prec_t)mpfr_precision); mpfr_set_z(f1, numerator , MPFR_RNDZ); mpfr_set_z(f2, denominator, MPFR_RNDZ); mpfr_div(f1, f1, f2, MPFR_RNDZ); mpfr_get_str(str_gmp_mpfr, & exp , 10, 0, f1, MPFR_RNDZ); *p_exp =( int ) exp ; mpfr_clear(f1); mpfr_clear(f2); mpz_clear(numerator); mpz_clear(denominator); mpq_clear(a); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | floatII floatII::operator+ ( floatII& f2) { //TODO: 0? int sign, pos; //align point floatII f1 = * this ; int int_len1 = strlen (f1.digits) - f1.point_pos_r; int int_len2 = strlen (f2.digits) - f2.point_pos_r; int frac_len1 = f1.point_pos_r; int frac_len2 = f2.point_pos_r; int max_int_len = int_len1 >= int_len2 ? int_len1 : int_len2 ; int max_frac_len = frac_len1 >= frac_len2 ? frac_len1 : frac_len2; floatII f1_old = f1; floatII f2_old = f2; //pos pos = max_frac_len; int len = max_int_len + max_frac_len; char * s1 = f1.extend_zero2( max_int_len-int_len1, max_frac_len-frac_len1); char * s2 = f2.extend_zero2( max_int_len-int_len2, max_frac_len-frac_len2); if (f1.minus == f2.minus) { //minus assign sign = f1.minus? -1 : +1; int * carry = ( int * ) malloc ( (len+1) * sizeof ( int )); char * r = ( char * ) malloc ( len ); memset (carry, 0, (len+1)* sizeof ( int )); char * q = s1+len-1; char * p = s2+len-1; int m; int k = 0; while (q >= s1) { m = chtoi(*q) + chtoi(*p) + carry[k]; if (m >= 10) { carry[k+1] += 1; r[k] = itoch(m-10); } else { r[k] = itoch(m); } p--; q--; k++; } char * str = ( char * ) malloc (len+1+1); //doesn't care if more int i = 0; int j; if (carry[k] > 0) str[i++] = itoch(carry[k]); for (j = 0; j < len; j++) str[i++] = r[len-1-j]; str[i] = '\0' ; floatII str_result(str, sign, pos); free (str); //? do it in destructor? free (r); free (carry); free (s1); free (s2); return str_result; } else { //to decide sign char * p = s1; char * q = s2; while (*p != '\0' ) // && *q != '\0' { if (chtoi(*p) != chtoi(*q)) break ; p++; q++; } if (*p == '\0' ) { free (s1); free (s2); floatII f4( "0" ); if (MY_DEBUG) printf ( "they are equal,minus result is 0\n" ); return f4; } else { bool t = chtoi(*p) > chtoi(*q) ? f1.minus : f2.minus; sign = t? -1 : +1; char * big = (*p > *q) ? s1 : s2; char * small = (*p > *q) ? s2 : s1; p = big + len-1; q = small + len-1; int * borrow = ( int * ) malloc ( (len) * sizeof ( int )); int n; char * r = ( char * ) malloc ( (len)); memset (borrow, 0, (len)* sizeof ( int )); int k = 0; while (p >= big) { if ( (chtoi(*p) + borrow[k]) >= chtoi(*q)) { n = chtoi(*p) + borrow[k] -chtoi(*q) ; } else { char * l = p-1; while ( chtoi(*l) == 0 ) { *l = '9' ; l--; } borrow[k] = 10; *l -= 1; n = chtoi(*p) + borrow[k] - chtoi(*q) ; } r[k] = itoch(n); p--; q--; k++; } //TODO: to remove leading 0s in integer part char * str = ( char * ) malloc (len+1); int i = 0; int j; for (j = 0; j < len; j++) str[i++] = r[len-1-j]; str[i] = '\0' ; floatII str_result2(str, sign, pos); free (str); free (r); free (borrow); free (s1); free (s2); return str_result2; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | floatII floatII::operator* ( int m) // 0<=m<=9 { //TODO: 0? int sign, pos; floatII& f1 = * this ; sign = f1.minus? -1: +1; //does not care //pos pos = f1.point_pos_r; //doesn't change int len = strlen (f1.digits); char * s = f1.digits; int * carry = ( int * ) malloc ( (len+1) * sizeof ( int )); char * r = ( char * ) malloc ( (len)); memset (carry, 0, (len+1)* sizeof ( int )); char * q = s+len-1; int d; int k = 0; while (q >= s) { d = chtoi(*q) * m + carry[k]; if (d >= 10) { carry[k+1] += d/10; d = d % 10; } r[k] = itoch(d); q--; k++; } //copied from add operation code part char * str = ( char * ) malloc (len+1+1); //doesn't care if more int i = 0; int j; if (carry[k] > 0) str[i++] = itoch(carry[k]); for (j = 0; j < len; j++) str[i++] = r[len-1-j]; str[i] = '\0' ; floatII str_result(str, sign, pos); free (str); //? do it in destructor? //copied from add operation code part -- end free (r); free (carry); return str_result; } floatII floatII::operator* ( const floatII& f2) { //TODO: 0? int sign; // pos; floatII& f1 = * this ; if (f1.minus == f2.minus) sign = +1; else sign = -1; char *p = f1.digits; char *q = f2.digits; //(choose the shorter to be multiplier?) floatII multi( "0" ); int len2 = strlen (f2.digits); for ( int i = 0; i < len2; i++) { floatII t1 = f1 * chtoi(q[i]); floatII t2 = shift_floatII(t1, len2 - f2.point_pos_r - 1 - i); multi = multi + t2; } multi.minus = (sign==-1)? true : false ; return multi; } floatII& shift_floatII (floatII& f, int m) { if (m > 0) { if (m >= f.point_pos_r) { f.extend_zero(0, m - f.point_pos_r); f.point_pos_r = 0; } else f.point_pos_r -= m; } else if (m < 0) { int int_len = strlen (f.digits) - f.point_pos_r; if (-m >= int_len) f.extend_zero(-m-int_len+1, 0); f.point_pos_r += -m; } return f; } |