mr_oydy@hotmail...'s profilehpho的共享空间PhotosBlogLists Tools Help

hpho的共享空间

多维存取适配器

因为使用了偏特化,所以需要VS2005以上编绎器编绎.
其原理很简单:

有n维T类型数组T arr1[D_n][D_n-1]...[D_1]和1维数组arr2[D_n*D_n-1*...*D_1];
所以sizeof(arr1)==sizeof(arr2);假设arr1和arr2内容相同.

d_1 = D_n-1 * ... * D_1;
...
d_n-1 = D_1;
则有多项式
f(a_1,...,a_n-1,a_n) = (a_1*d1) + ... + (a_n-1*d_n-1) + a_n;
arr1[a_1]...[a_n] = arr2[f(a_1,...,a_n-1,a_n)];
 
#include<iostream>
template<typename T, int sz>
class DimAdapter
{
public:
typedef T TYPE;
 DimAdapter(TYPE* p):ptr(p){pp = 0;}
private: 
  TYPE* ptr;
  int pp;
public:
  T& operator[](int i)
  {
    return ptr[i + pp];
  }
  DimAdapter& pos(int i){pp = i;return *this;}
  int dim(){return sz;}
};

template<typename T,int sz,int zz>
class DimAdapter<DimAdapter<T,sz>, zz>
{
private:
  DimAdapter<T,sz> low;
  int pp; 
public:
  typedef typename DimAdapter<T,sz>::TYPE TYPE;
  DimAdapter(TYPE* p):low(p){pp = 0;}
  DimAdapter<T,sz>& operator[](int i)
  {
    return low.pos(pp + low.dim() * i);
  }
 
  DimAdapter& pos(int i){pp = i;return *this;}
  int dim(){return zz * low.dim();}
};
#define ADAPTER_DIM2(t,d1,d2) \
 DimAdapter<DimAdapter<t,d2>,d1>
#define ADAPTER_DIM3(t,d1,d2,d3) \
 DimAdapter<ADAPTER_DIM2(t,d2,d3),d1>
#define ADAPTER_DIM4(t,d1,d2,d3,d4) \
 DimAdapter<ADAPTER_DIM3(t,d2,d3,d4),d1>
#define ADAPTER_DIM5(t,d1,d2,d3,d4,d5) \
 DimAdapter<ADAPTER_DIM4(t,d2,d3,d4,d5),d1>
#define ADAPTER_DIM6(t,d1,d2,d3,d4,d5,d6) \
 DimAdapter<ADAPTER_DIM5(t,d2,d3,d4,d5,d6),d1>
#define ADAPTER_DIM7(t,d1,d2,d3,d4,d5,d6,d7) \
 DimAdapter<ADAPTER_DIM6(t,d2,d3,d4,d5,d6,d7),d1>
/////////////////////////////////////////////
int main()
{
  using namespace std;
  int array[2*3*5];
 
  for(int i = 0;i<30;++i)
    array[i] = i;
   
  ADAPTER_DIM2(int,2,15) ad1 = array;
  ADAPTER_DIM2(int,6,5) ad2 = array;
  ADAPTER_DIM3(int,3,2,5) ad3 = array;
 
  for(int i = 0;i<2;++i)
    for(int j = 0;j<15;++j)
       cout << ad1[i][j] << " ";
      
  cout << endl;
   
  for(int i = 0;i<6;++i)
    for(int j = 0;j<5;++j)
       cout << ad2[i][j] << " ";
      
  cout << endl;
             
    for(int i = 0;i<3;++i)
      for(int j = 0;j<2;++j)
        for(int k = 0;k<5;++k)
   cout << ad3[i][j][k] << " ";
  return 0;
}

rational number 与 irrational number

    顺便一提,rational number 跟 irrational number 为什么被译成"有理数"与"无理数"的事情.
大家都会觉得很迷惑吧!原来日本大约十七,十八世纪接触西方数学的时候,他们就这么作了翻译,
后来中国人参照日本的译名依样采用,因而造成大错.其实rational这个字的字根是ratio,它是名词,
也就是比例的意思.如何把这个名词的字变化成形容词呢?一般的作法是直接在名词字尾加上"al",
但由于它最后一个字母"o"是母音,不能直接加"al"(因为a也是母音),需要先加一个字音之后再加"al",
于是就变成加上"n"之后再加上"al",而演变成ratio-n-al.其实rational这个字(在这里)跟"有理"一点都扯不上关系呢!
    当初的人搞错了,后来的人跟著错下去,真是"一失足成千古恨"呀....
摘自 数学传播32卷1期 
<再说sqrt(2)为无理数>

my_atan反正切

之前用泰勒展开式来写atan,结果收敛非常慢,现在用牛迭速度快很多了.
具体简单的复习一下牛迭:
  解非线性方程f(x)=0的牛顿法是把非线性方程线性化的一种近似方法。
把f(x)在x0点附近展开成泰勒级数 f(x) = f(x0)+(x-x0)f'(x0)+(x-x0)^2*f''(x0)/2! +… 取其线性部分,
作为非线性方程f(x) = 0的近似方程,即泰勒展开的前两项,
则有f(x0)+f'(x0)(x-x0)=f(x)=0 设f'(x0)≠0则其解为x1=x0-f(x0)/f'(x0) 这样,
得到牛顿法的一个迭代序列:x(n+1)=x(n)-f(x(n))/f'(x(n))。
 
代码:
#include <stdio.h>
#include <math.h>
 
double my_atan(double a){
  /*
  // fx = tanx - a
  // f'x = 1/(cosx)^2
  // fx = fa + f'a*(x-a)
  // [xn+1] = f[xn] + f'[xn]([xn]-a)
  // [xn+1] = [xn] - cos[xn]*sin[xn] + (a*cos[xn]^2)
  */

  double x = 0;
  while(fabs(sin(x)/cos(x)-a)>=1e-7)
    x -= (cos(x)*sin(x) - a*cos(x)*cos(x));
  return x;
}
 
void main(int argc, char *argv[])
{
  double RA = -3.1415/2;
  double i = RA;
  for(;i<-RA;i+=0.1)
  printf("%7f %7f\n", atan(i), my_atan(i));
}

my_pow幂函数

/*
 牛顿二项式: f(x) = (1+x)^a ; 仅当|x|<1, a<1才有效
 其泰勒展式: f(x) = f(a) + f'(a)(x-a) + (f''(a)(x-a)^2)/2! + ...
*/

double my_pow(double _x, double a){
  double r = 1.0f,x,A,X,L;
  long l = 1;
/* 
  处理如my_pow(4,0.5)情况. 1/my_pow(1/4,0.5);
  if(a<1. && _x>1.)
   x = 1./_x;
*/

  x = x - 1.0;
  A = a; X = x; L = l;
  /* 误差: 1/10! = 2.7557319223985890652557319223986e-7 */
  while(l<=10){
    r+=(A*X)/L;
    A*=(a-l);
    X*=x;
    L*=++l;
  }
/*
  return (a<1. && _x>1.)?1./r:r;
*/
  return r;
}
 
精度和强度都比math.h的pow弱, 仅作为基于数分的实践.

using Lagrange Interpolation Polynomial replace 'switch'


#define BASEFUN(x,a,b,c,d) (((x-b)*(x-c)*(x-d))/((a-b)*(a-c)*(a-d)))
#define CALC(op, l, r) BASEFUN(op,'+','-','*','/')*(l+r)+ \
                       BASEFUN(op,'-','+','*','/')*(l-r)+ \
                       BASEFUN(op,'*','+','-','/')*(l*r)+ \
                       BASEFUN(op,'/','+','-','*')*(l/r)

int main(int argc,char *argv[])
{
 char op;
 float lv,rv;
 scanf("%f%c%f",&lv,&op,&rv);
 printf("%.3f%c%.3f=%.3f\n",lv,op,rv,CALC(op,lv,rv));
 return 0;
}

Permutation Algorithm

void permutable(char* str, int len, char* out, int j){ // 打印所有元素的全排列
 int i;
 char tmp;
 if(len>=1){
  for(i=0; i<len; ++i){
   tmp=*str;*str=str[i];str[i]=tmp;
   out[j]=*str;
   permutable(str+1, len-1,out,j+1);
   tmp=*str;*str=str[i];str[i]=tmp;
  }
  if(len==1){
   out[j+1]=0;
   printf("%s\n",out);
  }
 }
}
------------------------------------------------------------------------------------
算法正确性证明:
用归纳法,
设:S是不为空的集合, 表示为S = {e_1,e_2,...,e_n}; {n|1,2,3,...};
1,当有2个元素时,交换(e_1,e_2)便得到另一个排列(e_2,e_1),即2!=2.
2,设当N个元素时成立.
3,则若有N+1个元素时,在N+1中取e_1,
  做交换(e_1,e_x) ;{x|2...n+1}, 便有新的一个拥有N个元素的子集(e_1,e_3,...,e_n+1),
  这时会有N个不同的这样的子集且再加上原来(e_2,e_3...,e_n+1),共有N+1个大小为N个元素的子集.
  然后因为元素为N个时此作法成立(即(N+1)*N*...*1=n!), 因此算法得证#
因为N个元素时成立,所以算法得证#
 

用stl的函数推砌trim()函数

#include <algorithm>
#include <functional>
 
#include <string>
 
namespace hpho{
template<typename Bgn, typename End, typename T>
Bgn trim(Bgn bgn, End end, T v){
  using namespace std;
  typedef reverse_iterator<char*,char>  RIter;
  End nend;

  copy(nend=find_if(bgn,end,bind1st(not_equal_to<char>(),v)), end, bgn); // 去前空格
 
  RIter rbgn(bgn+(end-nend)-1),                // 利用反转迭代器
         rend=reverse_iterator<char*,char>(bgn);

  find_if(rbgn,rend,bind1st(not_equal_to<char>(),v))[-1]='\0'; // 去后空格
  return bgn;
}
}
 
 
int main(void)
{
 using namespace hpho;
 std::string s="   abc  sss    ";
 trim(s.begin(),s.end(),' ');
 printf("[%s]",s.c_str());
 return 0;
}

初等行变换求逆矩阵

这是用初等行变换做的矩阵求逆
// 某行乘一个数
void f(double* v, int n, double d){
  int j;
  for(j=0;j<n;++j){
    v[j]*=d;
  }
}
 
// 某行乘一个数后加的另一行
void g(double* v1, double* v2, int n, double d){
  int j;
  double t;
  for(j=0;j<n;++j){
    t=v1[j]*d;
    v2[j]+=t;
  }
}
 
// 利用f()和g()两个变换求逆矩
void inverseM(double* m1, double* m2,int n){
   int i,j;
   double d;
   
   for(i=0;i<n;++i){
      d=1.0/m1[n*i+i];
     f(m1+n*i,n,d);f(m2+n*i,n,d);
     for(j=0;j<n;++j){
       if(i!=j){
          d=-m1[n*j+i];
          g(m1+n*i,m1+n*j,n,d);g(m2+n*i,m2+n*j,n,d);
     }
   }
 }
}

void printM(double* m, int n){
 int i,j;
 for(i=0;i<n;++i){
  for(j=0;j<n;++j){
   printf("%f ", m[n*i+j]);
  }
  printf("\n");
 }
}
 
int main(){
double m[9]={5.3,4.2,8.5,9.4,6.8,5.8,3.7,7.6,1.8};
double m1[9]={1,0,0,0,1,0,0,0,1};
inverseM(m,m1,3);
printM(m1,3);
}
 

把有中文英文混合的串分解为固定长度的子串

#include <ctype.h>
 
int truncation(char const* src, int slen, int idx, char* line, int len){
  int j=idx+len, k=0;
  while(idx<slen&&idx<j) {
    *line=src[idx];
    if(isprint((unsigned char)*line))
      ++k;
 ++idx;
 ++line;
  }
  if(idx>=slen) {
    *line='\0';
    return idx;
  }
  else if((len-k)>0&&(len-k)%2) {
    *(line-1)='\0';--idx;
  }
  *line='\0';
    return idx;
}
 
int main(){
  char text[]="一切从实际出发1,二氧化碳, abc三番五次123def";
  char buf[7];
  int i=0,l=strlen(text);
  while(i<l)
  {
    i=truncation(text,l,i,buf,sizeof(buf)-1);
    printf("%s\n",buf);
  }
  return 0;
}
 
/////////////////////////////////////////////////
1,必须注意char是有符号的.
2,使用isXXX函数时务必加强转型为unsigned char,理由是1.
3,若函数是需要加工串(如:统计,截断,...)时一般最好还是使用内建的类型指针.
 上述函数参数若用string或CString的话就必须先复制再统计,或时一边统计一边调用operator[]()或at()还处理每一个字符.这样增加了处理成本!

题目

一、题目:
这个题目比较变态 [所有相关帖子]

只用以下的符号:
~, !, ^,&, +, |, <<, >>.
实现 x?y:z
 
二、偶的答案:
y & ~x + x + !x | z & ~x + x + !!x;
三、分析:
整个式子由三部分构成:
1, ~x + x
2, !x 和 !!x
3, y & (1 + 2)
1,
无论x是什么数
~x + x 等同 ~x | x 等同 0xffffffff
2,
!x和!!x结果只会是0或1, 因为!操作符返回的是一个bool(true, false)
3, 1+2的意思
(~x + x + !x)和(~x + x + !!x)
意思就是:
0xffffffff + 0 或 0xffffffff + 1
而0xffffffff + 1等于0
4, 最终是要x!=0时产生0和0xffffffff, x==0时产生0xffffffff和0
这就做到(y & 0 | z & 0xffffffff) 或 (y & 0xffffffff | z & 0) 的效果.
 (y&0) 和 (z&0) 结是0
(y & 0xffffffff)和(z & 0xffffffff)都会自己y和z.
因为题目没给用"()"的原因所以要特别注意运算符级别因此没选用(~x | x)而是用(~x + x).
    看完这个后或许大家会有更好的答案, 期待中......!  :-)
注: 这里假定x,y,z为整形
posted on 2005-12-13 15:06 metaprogram的BLOG
 
Photo 1 of 3