Triển khai số dấu phẩy động nhị phân 64 bit 64 bit thông qua thao tác số nguyên


12

(Tôi đã gắn thẻ câu hỏi "C" trong thời gian này, nhưng nếu bạn biết về một ngôn ngữ khác hỗ trợ các công đoàn, bạn cũng có thể sử dụng câu hỏi đó.)

Nhiệm vụ của bạn là xây dựng bốn toán tử chuẩn + - * /cho cấu trúc sau:

union intfloat{
    double f;
    uint8_t h[8];
    uint16_t i[4];
    uint32_t j[2]; 
    uint64_t k;
    intfloat(double g){f = g;}
    intfloat(){k = 0;}
}

sao cho các thao tác chỉ tự thao tác hoặc truy cập vào phần nguyên (do đó không so sánh với nhân đôi bất kỳ lúc nào trong quá trình hoạt động) và kết quả hoàn toàn giống nhau (hoặc tương đương về mặt chức năng, trong trường hợp kết quả không phải là số như NaN) như thể hoạt động toán học tương ứng đã được áp dụng thẳng vào doublethay thế.

Bạn có thể chọn phần nguyên nào để thao tác, thậm chí có thể sử dụng các phần khác nhau giữa các toán tử khác nhau. (Bạn cũng có thể chọn xóa "không dấu" khỏi bất kỳ trường nào trong liên minh, mặc dù tôi không chắc liệu bạn có muốn làm điều đó không.)

Điểm của bạn là tổng độ dài của mã theo các ký tự cho mỗi trong số bốn toán tử. Điểm số thấp nhất chiến thắng.

Đối với những người trong chúng ta không quen thuộc với thông số kỹ thuật của IEEE 754, đây là một bài viết về nó trên Wikipedia.


Chỉnh sửa:

03-06 08:47 Đã thêm các hàm tạo vào cấu trúc intfloat. Bạn được phép sử dụng chúng để thử nghiệm, thay vì cài đặt thủ công / v.v.


1
Rất tiếc! Hãy cho tôi biết bạn có một giải pháp.
dmckee --- ex-moderator mèo con

4
Hmmm ... có lẽ sẽ tốt hơn nếu xác định intstructtheo nghĩa uint8_8, uint16_tvà như vậy là kích thước tuyệt đối short, intv.v. không được xác định theo tiêu chuẩn (mỗi loại có kích thước tối thiểu và có một thứ tự nghiêm ngặt về kích thước, nhưng đó là nó).
dmckee --- ex-moderator mèo con

1
Tôi đoán rằng đây là một thực hành tuyệt vời (và đầy thách thức) ngay cả khi không có kinh nghiệm
John Dvorak

3
Câu hỏi này có thể sử dụng tài liệu về cách làm tròn được xử lý và một bộ kiểm tra tốt.
Peter Taylor

4
Tôi chắc chắn rằng nó nằm trong thông số kỹ thuật, nhưng thông số thực sẽ có giá vài trăm USD. Có thể có những mô tả có sẵn miễn phí, nhưng IMO nên có một người hỏi để đưa vào loại chi tiết đó (hoặc ít nhất là một liên kết đến một trang web có khả năng vẫn còn tồn tại trong một vài năm) câu hỏi thay vì người trả lời hãy tự tìm kiếm các tài liệu cần thiết để biết câu hỏi thực sự muốn gì.
Peter Taylor

Câu trả lời:


11

C ++, ~ 1500 ký tự

Mở rộng các float thành biểu diễn điểm cố định 8000 chữ số nhị phân, thực hiện các thao tác trên đó, sau đó chuyển đổi trở lại.

// an "expanded" float.                                                                                                         
// n is nan, i is infinity, z is zero, s is sign.                                                                               
// nan overrides inf, inf overrides zero, zero overrides digits.                                                                
// sign is valid unless nan.                                                                                                    
// We store the number in fixed-point, little-endian.  Binary point is                                                          
// at N/2.  So 1.0 is N/2 zeros, one, N/2-1 zeros.                                                                              
#define N 8000
struct E {
  int n;
  int i;
  int z;
  long s;
  long d[N];
};
#define V if(r.n|r.i|r.z)return r
// Converts a regular floating-point number to an expanded one.                                                                 
E R(F x){
  long i,e=x.k<<1>>53,m=x.k<<12>>12;
  E r={e==2047&&m!=0,e==2047,e+m==0,x.k>>63};
  if(e)m+=1L<<52;else e++;
  for(i=0;i<53;i++)r.d[2925+e+i]=m>>i&1;
  return r;
}
E A(E x,E y){
  int i,c,v;
  if(x.s>y.s)return A(y,x);
  E r={x.n|y.n|x.i&y.i&(x.s^y.s),x.i|y.i,x.z&y.z,x.i&x.s|y.i&y.s|~x.i&~y.i&x.s&y.s};V;
  if(x.s^y.s){
    c=0;
    r.z=1;
    for(i=0;i<N;i++){
      v=x.d[i]-y.d[i]-c;
      r.d[i]=v&1;c=v<0;
      r.z&=~v&1;
    }
    if(c){x.s=1;y.s=0;r=A(y,x);r.s=1;}
  }else{
    c=0;
    for(i=0;i<N;i++){
      v=x.d[i]+y.d[i]+c;
      r.d[i]=v&1;c=v>1;
    }
  }
  return r;
}
E M(E x, E y){
  int i;
  E r={x.n|y.n|x.i&y.z|x.z&y.i,x.i|y.i,x.z|y.z,x.s^y.s};V;
  E s={0,0,1};
  for(i=0;i<6000;i++)y.d[i]=y.d[i+2000];
  for(i=0;i<4000;i++){
    if(x.d[i+2000])s=A(s,y);
    y=A(y,y);
  }
  s.s^=x.s;
  return s;
}
// 1/d using Newton-Raphson:                                                                                                    
// x <- x * (2 - d*x)                                                                                                           
E I(E d){
  int i;
  E r={d.n,d.z,d.i,d.s};V;
  E t={};t.d[4001]=1;
  for(i=N-1;i>0;i--)if(d.d[i])break;
  E x={0,0,0,d.s};x.d[N-i]=1;
  d.s^=1;
  for(i=0;i<10;i++)x=M(x,A(t,M(d,x)));
  return x;
}
// Convert expanded number back to regular floating point.                                                                      
F C(E x){
  long i,j,e,m=0;
  for(i=N-1;i>=0;i--)if(x.d[i])break;
  for(j=0;j<N;j++)if(x.d[j])break;
  if(i>0&x.d[i-53]&(j<i-53|x.d[i-52])){E y={0,0,0,x.s};y.d[i-53]=1;return C(A(x,y));}
  if(i<2978){e=0;for(j=0;j<52;j++)m+=x.d[j+2926]<<j;}
  else if(i<5024){e=i-2977;for(j=0;j<52;j++)m+=x.d[i+j-52]<<j;}
  else x.i=1;
  if(x.z)e=m=0;
  if(x.i){e=2047;m=0;}
  if(x.n)e=m=2047;
  F y;y.k=x.s<<63|e<<52|m;return y;
}
// expand, do op, unexpand                                                                                                      
F A(F x,F y){return C(A(R(x),R(y)));}
F S(F x,F y){y.k^=1L<<63;return A(x,y);}
F M(F x,F y){return C(M(R(x),R(y)));}
F D(F x,F y){return C(M(R(x),I(R(y))));}

Tôi quá lười biếng để loại bỏ tất cả các khoảng trắng và dòng mới để có được số đếm golf chính xác, nhưng nó có khoảng 1500 ký tự.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.