用C++实现带单位的数值计算

在科学计算中的数值量常带有单位,而不同单位的量容易相互混淆。下面的简单的C++代码实现了带单位的数值量计算。

// 用 g++-4.8.2编译,编译选项: -std=c++11
// hang_ke@sohu.com

template <class T, int u1, int u2 = 0, int u3 = 0, int u4 = 0, int u5 = 0>
class Unit {
    template <class S, int v1, int v2, int v3, int v4, int v5> friend class Unit;
    T value;
public:
    typedef T value_type;
    typedef Unit unit_type;
    
    Unit() : value(0) {}
    Unit(T v) : value(v) {}

    Unit<T, u1*2, u2*2, u3*2, u4*2, u5*2> pow2() const {
        return value * value;
    }
    Unit<T, u1*3, u2*3, u3*3, u4*3, u5*3> pow3() const {
        return value * value * value;
    }

    Unit operator+(Unit unit) const { return value + unit.value; }
    Unit operator-(Unit unit) const { return value - unit.value; }
    Unit operator*(T v) const { return value * v; }
    template<int v1, int v2, int v3, int v4, int v5>
    Unit<T, u1+v1, u2+v2, u3+v3, u4+v4, u5+v5> operator*(Unit<T, v1, v2, v3, v4, v5> unit) const {
        return value * unit.value;
    }
    template<int v1, int v2, int v3, int v4, int v5>
    Unit<T, u1-v1, u2-v2, u3-v3, u4-v4, u5-v5> operator/(Unit<T, v1, v2, v3, v4, v5> unit) const {
        return value / unit.value;
    }

    explicit operator T() const { return value; }
    T inUnit(Unit unit) const { return value / unit.value; }
};

template<class T, int u1, int u2, int u3, int u4, int u5>
Unit<T, u1, u2, u3, u4, u5> operator*(T v, Unit<T, u1, u2, u3, u4, u5> unit) {
    return unit * v;
}

typedef Unit<double, 1, 0, 0> Mass;
typedef Unit<double, 0, 1, 0> Length;
typedef Unit<double, 0, 0, 1> Time;

typedef Unit<double, 0, 2, 0> Area;
typedef Unit<double, 0, 3, 0> Volume;

const Mass kilogram(1), gram(0.001);    // 值为1代表基本单位。
const Length meter(1), kilometer(1000);
const Time second(1), minute(60), hour(3600);
const auto second2 = second.pow2();

typedef decltype(meter/second) Speed;   // 应可写为 decltype(Length/Time)?
typedef decltype(meter/second2) Acceleration;
typedef decltype(kilogram*meter/second2) Force;

const Force newton(1);
const Acceleration G = 9.8 * meter / second2;

#include <iostream>
int main() {
    using namespace std;
    Length length = 5. * kilometer;
    Time time = 0.5 * hour;
    Speed speed = length / time;
    Force force = 50000. * gram * G;
    cout << "speed(m/s) = " << (double)speed << endl
         << "speed(km/h) = " << speed.inUnit(kilometer/hour) << endl
         << "force(N) = " << (double)force << endl;

    Speed speeds[] = { 1., 2., 3., 4., 5. };    // 原单位为km/h,需要转换。
    cout << "speeds(m/s)[] = " << endl;
    for (Speed& s : speeds) s = (double)s * kilometer / hour,
                            cout << "    " << (double)s << endl;
    return 0;
}
/* 程序输出
speed(m/s) = 2.77778
speed(km/h) = 10
force(N) = 490
speeds(m/s)[] =
    0.277778
    0.555556
    0.833333
    1.11111
    1.38889
*/

说明:

1. 程序用C++11编写,但并非必要,用到的C++11特性可以绕开。
2. 选择基本单位时不必根据标准单位制,如可以用毫米而不是米,以提高数值精度。
3. 代码不支持一些功能,如非倍数的单位转换(如摄氏度-华氏度)。
4. 编译器应当能优化掉主要开销,如数量与单位常量的乘积在代码内联后应能使常量乘积合并为常数。
3. boost(www.boost.org)也提供了units库,但实现代码过于复杂不可读也不易学。议论:开源库(许多商业库也公开源代码)的代码应当清晰可读,这有助于用户检查代码、学习、改进(这是用户的权利,也是软件公司营造独特价值、占领用户市场的方法)。一些质量欠佳的开源库实际上在鼓励竞争及自行编写。
4. C++ STL的编译错误信息难以理解。这也鼓励商业编译器市场以及对C++语言的扩展改进。例如,下面的代码用非虚函数接口来约束template参数类型(参见 http://bbs.csdn.net/topics/390820400):

struct A {
    void greet() = 0;   // 非虚函数,C++语法扩展
    A() = 0;            // constructor
};
template <class T: A>   // T不必显式继承A
class X {
    void greet() {
        T a;
        a.greet();
    }
};
顺便说一句,csdn应支持用email发表与获取blog文章(参见newsgroup),在网页上编辑不方便。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用 C++ 实现魔兽争霸单位寻路的基本步骤: 1. 定义节点结构体,包含节点坐标、通行性、移动代价等信息。 ``` struct Node { int x, y; // 节点坐标 bool pass; // 是否可通行 int cost; // 移动代价 // 其他信息... }; ``` 2. 定义 A* 算法中的开放列表和关闭列表,以及计算估价函数的方法。 ``` // 开放列表和关闭列表 vector<Node> openList; vector<Node> closedList; // 计算估价函数 int heuristic(Node& node, Node& target) { int dx = abs(node.x - target.x); int dy = abs(node.y - target.y); return dx + dy; // 简单使用曼哈顿距离作为估价函数 } ``` 3. 实现 A* 算法的主体部分,包括将起点加入开放列表、从开放列表中取出节点、扩展节点、加入关闭列表等步骤。 ``` // A* 算法主体 bool aStar(Node& start, Node& target, vector<vector<Node>>& map) { openList.push_back(start); while (!openList.empty()) { // 取出估价函数值最小的节点 Node current = openList[0]; int currentIndex = 0; for (int i = 1; i < openList.size(); i++) { if (heuristic(openList[i], target) < heuristic(current, target)) { current = openList[i]; currentIndex = i; } } // 到达目标节点 if (current.x == target.x && current.y == target.y) { // 返回 true 或者记录路径等信息 return true; } // 从开放列表中删除当前节点,加入关闭列表 openList.erase(openList.begin() + currentIndex); closedList.push_back(current); // 扩展当前节点 vector<Node> neighbors; if (current.x > 0) neighbors.push_back(map[current.x - 1][current.y]); if (current.y > 0) neighbors.push_back(map[current.x][current.y - 1]); if (current.x < map.size()) neighbors.push_back(map[current.x + 1][current.y]); if (current.y < map[0].size()) neighbors.push_back(map[current.x][current.y + 1]); for (Node neighbor : neighbors) { // 跳过不可通行的节点和已经在关闭列表中的节点 if (!neighbor.pass || find(closedList.begin(), closedList.end(), neighbor) != closedList.end()) { continue; } // 计算新的移动代价 int newCost = current.cost + neighbor.cost; // 如果新的移动代价更小,或者邻居节点不在开放列表中,则更新邻居节点的代价和父节点 bool inOpenList = find(openList.begin(), openList.end(), neighbor) != openList.end(); if (newCost < neighbor.cost || !inOpenList) { neighbor.cost = newCost; neighbor.parent = &current; if (!inOpenList) { openList.push_back(neighbor); } } } } // 无法到达目标节点,返回 false 或者其他信息 return false; } ``` 4. 在实际使用时,需要根据地图和单位的移动能力等因素,初始化节点的通行性和移动代价等信息。 ``` // 初始化地图 vector<vector<Node>> map; for (int i = 0; i < mapSize; i++) { vector<Node> row; for (int j = 0; j < mapSize; j++) { Node node; node.x = i; node.y = j; node.pass = checkPassability(i, j); // 根据地形信息判断通行性 node.cost = calculateCost(i, j); // 根据地形和单位移动能力计算移动代价 row.push_back(node); } map.push_back(row); } // 初始化起点和终点 Node start = map[startX][startY]; Node target = map[targetX][targetY]; // 调用 A* 算法 bool success = aStar(start, target, map); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值