如果我们不想用系统自带的log
和exp
函数,想要自定义一个可以预先计算出来的数据对照表,供使用者在程序mysqrt
中查表使用。
1. 删除系统的库函数调用
- 删除对log和exp函数的检查。
在MathFunctions/CMakeLists.txt,删除下面的内容:
# does this system provide the log and exp functions?
include(CheckSymbolExists)
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(NOT (HAVE_LOG AND HAVE_EXP))
unset(HAVE_LOG CACHE)
unset(HAVE_EXP CACHE)
set(CMAKE_REQUIRED_LIBRARIES "m")
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_link_libraries(MathFunctions PRIVATE m)
endif()
endif()
# add compile definitions
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
- 删除mysqrt.cxx中对
HAVE_LOG
andHAVE_EXP
的检查
// if we have both log and exp then use them
#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = exp(log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;
// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
#endif
并删除#include <cmath>.
2. 添加生成表的脚本
在MathFunctions
文件夹内添加一个新文件MakeTable.cxx
,这个文件中的代码内容:
// A simple program that builds a sqrt table
#include <cmath>
#include <fstream>
#include <iostream>
int main(int argc, char* argv[])
{
// make sure we have enough arguments
if (argc < 2) {
return 1;
}
std::ofstream fout(argv[1], std::ios_base::out);
const bool fileOpen = fout.is_open();
if (fileOpen) {
fout << "double sqrtTable[] = {" << std::endl;
for (int i = 0; i < 10; ++i) {
fout << sqrt(static_cast<double>(i)) << "," << std::endl;
}
// close the table with a zero
fout << "0};" << std::endl;
fout.close();
}
return fileOpen ? 0 : 1; // return 0 if wrote the file
}
从上面的代码内容中可以看出来,这个代码段可以产生一个table,并且我们把这个table存到另一个文件中去。
为了能够让上面的代码能够在预编译的时候产生table,我们需要进行下面的工作:
- 添加其为可执行文件
在MathFunctions/CMakeLists.txt
的头上添加下面的内容add_executable(MakeTable MakeTable.cxx)
- 添加一个自定义的命令,去定义如何产生table.h
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
)
Table,h
为mysqrt.cxx
添加对Table.h
的依赖
因为mysqrt.cxx
也在MathFunctions这一层,所以,为了添加这个依赖,我们在MathFunctions/CMakeLists.txt中添加下面的代码:
add_library(MathFunctions
mysqrt.cxx
${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
)
- 重写
mysqrt.cxx
去调用Table.h
中的功能
double mysqrt(double x)
{
if (x <= 0) {
return 0;
}
// use the table to help find an initial value
double result = x;
if (x >= 1 && x < 10) {
std::cout << "Use the table to help find an initial value " << std::endl;
result = sqrtTable[static_cast<int>(x)];
}
// do ten iterations
for (int i = 0; i < 10; ++i) {
if (result <= 0) {
result = 0.1;
}
double delta = x - (result * result);
result = result + 0.5 * delta / result;
std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
}
return result;
}
- 执行CMake去配置工程
当工程make的时候,它首先建立MakeTable,然后产生Table.h, 然后编译mysqrt.cxx去包含Table.h这个库函数。