C ++ Thực tiễn tốt nhất để xử lý nhiều hằng số, biến trong mã khoa học


17

Tôi đang phát triển một mã để mô phỏng dòng chất lỏng với các chất sinh học có trong dòng chảy. Điều này liên quan đến các phương trình Navier - Stokes tiêu chuẩn kết hợp với một số mô hình sinh học bổ sung. Có nhiều tham số / hằng số.

Tôi có các hàm viết để xử lý các tính toán chính, nhưng một vấn đề tôi gặp phải là số lượng lớn các hằng số / tham số mà các tính toán này phụ thuộc vào. Có vẻ rườm rà khi truyền 10-20 đối số cho một hàm.

Một cách khác là tạo tất cả các biến toàn cục, nhưng tôi biết điều này được tán thành trong C ++.

Cách tiêu chuẩn để xử lý nhiều đầu vào cho một chức năng là gì? Tôi có nên tạo một cấu trúc và vượt qua điều đó thay vào đó?

Cảm ơn bạn


7
Nếu có thể, hãy thử đánh giá các hằng số tại thời điểm biên dịch bằng constexpr. Tôi cố gắng bao gồm hầu hết những thứ này trong một tệp tiêu đề riêng biệt. Đối với các biến, tôi đã thấy rằng một lớp riêng biệt có lợi ích, nhưng với chi phí có nhiều lỗi hơn vì bạn phải khởi tạo lớp trước khi chuyển vào hàm.
Biswajit Banerjee

3
Điều này thật khó để trả lời đúng nếu không có một số mẫu mã. Tôi có nên tạo một cấu trúc và vượt qua điều đó thay vào đó? Nói chung, có, đây hoàn toàn là cách thông thường để đi. Nhóm các tham số / hằng số theo ý nghĩa của chúng.
Kirill

1
"Một cách khác là tạo ra tất cả các biến toàn cục, nhưng tôi biết điều này được tán thành trong C ++" Phải không?
Cuộc đua nhẹ nhàng với Monica

1
Họ thực sự, thực sự hằng? Điều gì nếu bạn muốn áp dụng mô hình của bạn trong một tên miền khác? Tôi sẽ khuyên bạn nên đặt chúng trong một lớp học nhỏ. Điều đó ít nhất mang đến cho bạn một chút linh hoạt trong tương lai
André

@ André Hầu hết trong số họ được điều khiển bởi người dùng thông qua tệp tham số, đó là lý do tại sao tôi đồng ý rằng giải pháp lớp là tốt nhất.
EternusVia

Câu trả lời:


13

Nếu bạn có các hằng số sẽ không thay đổi trước khi chạy, hãy khai báo chúng trong tệp tiêu đề:

//constants.hpp
#ifndef PROJECT_NAME_constants_hpp
#define PROJECT_NAME_constants_hpp
namespace constants {
  constexpr double G        = 6.67408e-11;
  constexpr double M_EARTH  = 5.972e24;
  constexpr double GM_EARTH = G*M_EARTH; 
}
#endif

//main.cpp
using namespace constants;
auto f_earth = GM_EARTH*m/r/r;  //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too

Lý do tại sao bạn muốn làm điều này là vì nó cho phép trình biên dịch tính toán các giá trị không đổi trước thời gian chạy, điều này rất tốt nếu bạn có nhiều trong số chúng.

Bạn cũng có thể sử dụng một lớp đơn giản để truyền các giá trị xung quanh:

class Params {
 public:
  double a,b,c,d;
  Params(std::string config_file_name){
    //Load configuration here
  }
};

void Foo(const Params &params) {
  ...
}

int main(int argc, char **argv){
  Params params(argv[1]);
  Foo(params);
}

Tất cả các câu trả lời tuyệt vời nhưng giải pháp lớp học hoạt động tốt nhất cho tình huống của tôi.
EternusVia

8
Nếu bạn thực hiện các biến toàn cục constexpr, ít nhất hãy đặt chúng vào một biến namespaceđể chúng không bước vào bất kỳ biểu tượng toàn cầu nào khác. Sử dụng một biến toàn cầu được gọi Glà chỉ gọi cho rắc rối.
Wolfgang Bangerth

1
Tại sao bạn dẫn đầu bao gồm các vệ sĩ với _? Bạn không bao giờ nên viết bất cứ điều gì bắt đầu bằng _, bạn có nguy cơ va chạm với các trình biên dịch. Bạn nên làm một cái gì đó như ifndef PROJECT_NAME_FILE_NAME_EXTENSION. Ngoài ra, không chắc chắn lý do tại sao bạn viết hoa các hằng số, nhưng không bao gồm các macro bảo vệ. Bạn thường muốn viết hoa tất cả các macro, đặc biệt là vì chúng không hợp vệ sinh. Đối với viết hoa hằng không có ý nghĩa nói chung . Glà tốt vì SI của nó, nhưng mass_earth phù hợp hơn và phải đủ điều kiện với một không gian tên để biểu thị toàn cầu tức là constants::mass_earth.
whn

12

Một cách khác có thể phù hợp với lối suy nghĩ của bạn là sử dụng một không gian tên (hoặc không gian tên lồng nhau) để nhóm các hằng số đúng. Một ví dụ có thể là:

namespace constants {
   namespace earth {
      constexpr double G = 6.67408e-11;
      constexpr double Mass_Earth = 5.972e24;
      constexpr double GM = G*Mass_Earth;
   }// constant properties about Earth

   namespace fluid {
      constexpr double density = 0.999; // g/cm^3
      constexpr double dyn_viscosity = 1.6735; //mPa * s
   }// constants about fluid at 2C

   // ... 

} // end namespace for constants

Sử dụng kỹ thuật trên, bạn có thể bản địa hóa các hằng tham chiếu đến một số tệp và không gian tên mong muốn, làm cho chúng được kiểm soát nhiều hơn các biến toàn cục trong khi nhận được một số lợi ích tương tự. Khi bạn sử dụng các hằng số, nó đơn giản như cách làm:

constexpr double G_times_2 = 2.0*constants::earth::G;

Nếu bạn không thích các chuỗi không gian tên lồng nhau, bạn luôn có thể rút ngắn mọi thứ khi cần bằng cách sử dụng bí danh không gian tên:

namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;

2
Đây là một cách tiếp cận, được theo sau bởi OpenFOAM , xem một ví dụ ngẫu nhiên về mã nguồn của OpenFOAM . OpenFOAM là thư viện mã C ++ thực hiện phương pháp thể tích hữu hạn, được sử dụng rộng rãi trong động lực học chất lỏng.
Dohn Joe

1

Một cách mà tôi làm là sử dụng singleton.

Khi bạn bắt đầu chương trình, bạn khởi tạo singleton và điền nó với dữ liệu không đổi (có thể từ tệp thuộc tính mà bạn có để chạy). Bạn nhận được điều này trong mỗi lớp mà bạn cần các giá trị và chỉ cần sử dụng nó.


Cảnh báo: Thỉnh thoảng tôi có các singletons tuần tự truy cập trong mã đa luồng. Vì vậy, bạn có thể muốn kiểm tra điều này như là một phần của giai đoạn hồ sơ của bạn.
Richard

Tôi chắc chắn sẽ không đưa chúng vào một đơn ... Trong thực tế, các hằng số đó sẽ thay đổi trong tương lai khi (không phải) nếu bạn áp dụng mô hình của mình trong một miền khác. Có một singleton làm cho nó rất khó để kiểm tra với các thông số khác nhau.
André

Chúng đều là hằng số. Không cần ở đây cho một người độc thân. Một lớp truy cập tĩnh là một sử dụng tốt hơn ở đây. Thậm chí tốt hơn sẽ là một lớp tĩnh nơi các giá trị được kéo từ tệp cấu hình (vì vậy nếu người dùng cuối của bạn thấy có lỗi hoặc muốn chính xác hơn, họ có thể điều chỉnh tệp cấu hình mà không cần bản dựng mới).
Scuba Steve

Singletons hiếm khi, nếu có, là một ý tưởng tốt. Phụ thuộc tiêm là một giải pháp linh hoạt và sạch sẽ hơn nhiều. Tuy nhiên, chỉ với các hằng số, tôi muốn nói chỉ cần giữ các hằng số trong một tiêu đề ở đâu đó.
mascoj
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.