diff --git a/Makefile b/Makefile index b3a16a7..a49b7ef 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,7 @@ BUILD_LIST+=exprtk_simple_example_11 BUILD_LIST+=exprtk_simple_example_12 BUILD_LIST+=exprtk_simple_example_13 BUILD_LIST+=exprtk_simple_example_14 +BUILD_LIST+=exprtk_simple_example_15 all: $(BUILD_LIST) @@ -89,6 +90,9 @@ exprtk_simple_example_13: exprtk_simple_example_13.cpp exprtk.hpp exprtk_simple_example_14: exprtk_simple_example_14.cpp exprtk.hpp $(COMPILER) $(OPTIONS) exprtk_simple_example_14 exprtk_simple_example_14.cpp $(LINKER_OPT) +exprtk_simple_example_15: exprtk_simple_example_15.cpp exprtk.hpp + $(COMPILER) $(OPTIONS) exprtk_simple_example_15 exprtk_simple_example_15.cpp $(LINKER_OPT) + pgo: exprtk_test.cpp exprtk_benchmark.cpp exprtk.hpp $(COMPILER) $(BASE_OPTIONS) -O3 -march=native -fprofile-generate -o exprtk_benchmark exprtk_benchmark.cpp $(LINKER_OPT) ./exprtk_benchmark @@ -111,6 +115,7 @@ strip_bin: strip -s exprtk_simple_example_12 strip -s exprtk_simple_example_13 strip -s exprtk_simple_example_14 + strip -s exprtk_simple_example_15 valgrind_check: valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_test_valgrind.log -v ./exprtk_test @@ -129,6 +134,7 @@ valgrind_check: valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_12_valgrind.log -v ./exprtk_simple_example_12 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_13_valgrind.log -v ./exprtk_simple_example_13 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_14_valgrind.log -v ./exprtk_simple_example_14 + valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_15_valgrind.log -v ./exprtk_simple_example_15 clean: rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch diff --git a/exprtk.hpp b/exprtk.hpp index 03bd67e..2fc9613 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -286,10 +286,10 @@ namespace exprtk "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", "expm1", "false", "floor", "for", "frac", "grad2deg", "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", "like", "log", "log10", "log2", "logn", "log1p", "mand", "max", "min", "mod", "mor", - "mul", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", "repeat", - "root", "round", "roundn", "sec", "sgn", "shl", "shr", "sin", "sinc", "sinh", "sqrt", - "sum", "swap", "switch", "tan", "tanh", "true", "trunc", "until", "var", "while", - "xnor", "xor", "&", "|" + "mul", "ncdf", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", + "repeat", "root", "round", "roundn", "sec", "sgn", "shl", "shr", "sin", "sinc", + "sinh", "sqrt", "sum", "swap", "switch", "tan", "tanh", "true", "trunc", "until", + "var", "while", "xnor", "xor", "&", "|" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); @@ -428,6 +428,7 @@ namespace exprtk static const double _2_pi = 0.636619772367581343076; static const double _180_pi = 57.295779513082320876798; static const double log2 = 0.693147180559945309417; + static const double sqrt2 = 1.414213562373095048801; } namespace details @@ -852,6 +853,21 @@ namespace exprtk return erfc_impl(static_cast(v),real_type_tag()); } + template + inline T ncdf_impl(T v, real_type_tag) + { + T cnd = T(0.5) * (T(1) + erf_impl( + abs_impl(v,real_type_tag()) / + numeric::constant::sqrt2,real_type_tag())); + return (v < 0) ? (T(1) - cnd) : cnd; + } + + template + inline T ncdf_impl(T v, int_type_tag) + { + return ncdf_impl(static_cast(v),real_type_tag()); + } + template inline T sinc_impl(T v, real_type_tag) { @@ -864,7 +880,7 @@ namespace exprtk template inline T sinc_impl(T v, int_type_tag) { - return erfc_impl(static_cast(v),real_type_tag()); + return sinc_impl(static_cast(v),real_type_tag()); } template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } @@ -1158,6 +1174,7 @@ namespace exprtk exprtk_define_unary_function(sgn ) exprtk_define_unary_function(erf ) exprtk_define_unary_function(erfc ) + exprtk_define_unary_function(ncdf ) exprtk_define_unary_function(frac ) exprtk_define_unary_function(trunc) #undef exprtk_define_unary_function @@ -3217,10 +3234,10 @@ namespace exprtk e_tanh , e_cot , e_clamp , e_iclamp , e_inrange , e_sgn , e_r2d , e_d2r , e_d2g , e_g2d , e_hypot , e_notl , - e_erf , e_erfc , e_frac , e_trunc , - e_assign , e_addass , e_subass , e_mulass , - e_divass , e_modass , e_in , e_like , - e_ilike , e_multi , e_swap , + e_erf , e_erfc , e_ncdf , e_frac , + e_trunc , e_assign , e_addass , e_subass , + e_mulass , e_divass , e_modass , e_in , + e_like , e_ilike , e_multi , e_swap , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, @@ -3320,6 +3337,7 @@ namespace exprtk case e_sgn : return numeric::sgn (arg); case e_erf : return numeric::erf (arg); case e_erfc : return numeric::erfc (arg); + case e_ncdf : return numeric::ncdf (arg); case e_frac : return numeric::frac (arg); case e_trunc : return numeric::trunc(arg); default : return std::numeric_limits::quiet_NaN(); @@ -3465,18 +3483,19 @@ namespace exprtk e_sqrt , e_tan , e_tanh , e_cot , e_sec , e_csc , e_r2d , e_d2r , e_d2g , e_g2d , e_notl , e_sgn , - e_erf , e_erfc , e_frac , e_trunc , - e_uvouv , e_vov , e_cov , e_voc , - e_vob , e_bov , e_cob , e_boc , - e_vovov , e_vovoc , e_vocov , e_covov , - e_covoc , e_vovovov , e_vovovoc , e_vovocov , - e_vocovov , e_covovov , e_covocov , e_vocovoc , - e_covovoc , e_vococov , e_sf3ext , e_sf4ext , - e_nulleq , e_vector , e_vecelem , e_vecdefass , - e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , - e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , - e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , - e_vecunaryop , e_break , e_continue , e_swap + e_erf , e_erfc , e_ncdf , e_frac , + e_trunc , e_uvouv , e_vov , e_cov , + e_voc , e_vob , e_bov , e_cob , + e_boc , e_vovov , e_vovoc , e_vocov , + e_covov , e_covoc , e_vovovov , e_vovovoc , + e_vovocov , e_vocovov , e_covovov , e_covocov , + e_vocovoc , e_covovoc , e_vococov , e_sf3ext , + e_sf4ext , e_nulleq , e_vector , e_vecelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_break , e_continue , + e_swap }; typedef T value_type; @@ -7692,6 +7711,7 @@ namespace exprtk exprtk_define_unary_op(log10) exprtk_define_unary_op(log2 ) exprtk_define_unary_op(log1p) + exprtk_define_unary_op(ncdf ) exprtk_define_unary_op(neg ) exprtk_define_unary_op(notl ) exprtk_define_unary_op(pos ) @@ -10940,6 +10960,7 @@ namespace exprtk register_op( "not",e_notl , 1) register_op( "erf",e_erf , 1) register_op( "erfc",e_erfc , 1) + register_op( "ncdf",e_ncdf , 1) register_op( "frac",e_frac , 1) register_op( "trunc",e_trunc , 1) register_op( "atan2",e_atan2 , 2) @@ -16789,8 +16810,8 @@ namespace exprtk (details::e_d2r == operation) || (details::e_d2g == operation) || (details::e_g2d == operation) || (details::e_notl == operation) || (details::e_sgn == operation) || (details::e_erf == operation) || - (details::e_erfc == operation) || (details::e_frac == operation) || - (details::e_trunc == operation); + (details::e_erfc == operation) || (details::e_ncdf == operation) || + (details::e_frac == operation) || (details::e_trunc == operation); } inline bool sf3_optimizable(const std::string& sf3id, trinary_functor_t& tfunc) @@ -17558,6 +17579,7 @@ namespace exprtk case_stmt(details:: e_sgn,details:: sgn_op) \ case_stmt(details:: e_erf,details:: erf_op) \ case_stmt(details:: e_erfc,details:: erfc_op) \ + case_stmt(details:: e_ncdf,details:: ncdf_op) \ case_stmt(details:: e_frac,details:: frac_op) \ case_stmt(details::e_trunc,details::trunc_op) \ @@ -23000,6 +23022,7 @@ namespace exprtk register_unary_op(details:: e_sgn,details:: sgn_op) register_unary_op(details:: e_erf,details:: erf_op) register_unary_op(details:: e_erfc,details:: erfc_op) + register_unary_op(details:: e_ncdf,details:: ncdf_op) register_unary_op(details:: e_frac,details:: frac_op) register_unary_op(details::e_trunc,details::trunc_op) #undef register_unary_op diff --git a/exprtk_simple_example_15.cpp b/exprtk_simple_example_15.cpp new file mode 100644 index 0000000..bb11902 --- /dev/null +++ b/exprtk_simple_example_15.cpp @@ -0,0 +1,94 @@ +/* + ************************************************************** + * C++ Mathematical Expression Toolkit Library * + * * + * Simple Example 15 * + * Author: Arash Partow (1999-2014) * + * URL: http://www.partow.net/programming/exprtk/index.html * + * * + * Copyright notice: * + * Free use of the Mathematical Expression Toolkit Library is * + * permitted under the guidelines and in accordance with the * + * most current version of the Common Public License. * + * http://www.opensource.org/licenses/cpl1.0.php * + * * + ************************************************************** +*/ + + +#include +#include +#include +#include +#include "exprtk.hpp" + + +template +void black_scholes_merton_model() +{ + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + std::string bsm_model_program = + " var d1 := (log(s / x) + (r + v^2 / 2) * t) / (v * sqrt(t)); " + " var d2 := d1 - v * sqrt(t); " + " " + " if(callput_flag == 'call') " + " s * ncdf(d1) - x * e^(-r * t) * ncdf(d2); " + " else if(callput_flag == 'put') " + " x * e^(-r * t) * ncdf(-d2) - s * ncdf(-d1); " + " "; + + T s = T(60.00); // Stock price + T x = T(65.00); // Strike price + T t = T( 0.25); // Years to maturity + T r = T( 0.08); // Risk free rate + T v = T( 0.30); // Volatility + + std::string callput_flag; + + static const T e = exprtk::details::numeric::constant::e; + + symbol_table_t symbol_table; + symbol_table.add_variable("s",s); + symbol_table.add_variable("x",x); + symbol_table.add_variable("t",t); + symbol_table.add_variable("r",r); + symbol_table.add_variable("v",v); + symbol_table.add_constant("e",e); + symbol_table.add_stringvar("callput_flag",callput_flag); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + + parser.compile(bsm_model_program,expression); + + { + callput_flag = "call"; + T bsm = expression.value(); + + printf("BSM(%s,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f) = %10.6f\n", + callput_flag.c_str(), + s,x,t,r,v, + bsm); + } + + { + callput_flag = "put"; + T bsm = expression.value(); + + printf("BSM(%s,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f) = %10.6f\n", + callput_flag.c_str(), + s,x,t,r,v, + bsm); + } +} + +int main() +{ + black_scholes_merton_model(); + return 0; +} diff --git a/readme.txt b/readme.txt index b22377f..2ce9d03 100644 --- a/readme.txt +++ b/readme.txt @@ -17,7 +17,7 @@ arithmetic operations, functions and processes: (01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp, expm1, floor, frac, log, log10, log1p, log2, - logn, max, min, mul, nequal, root, round, + logn, max, min, mul, ncdf, nequal, root, round, roundn, sgn, sqrt, sum, swap, trunc (02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2, @@ -283,6 +283,8 @@ of C++ compilers: | mul | Product of all the inputs. | | | (eg: mul(x,y,z,w,u,v,t) == (x * y * z * w * u * v * t)) | +----------+---------------------------------------------------------+ +| ncdf | Normal cumulative distribution function. (eg: ncdf(x)) | ++----------+---------------------------------------------------------+ | nequal | Not-equal test between x and y using normalized epsilon | +----------+---------------------------------------------------------+ | root | Nth-Root of x. where n is a positive integer. | @@ -1343,6 +1345,7 @@ in a compilation failure. (16) exprtk_simple_example_12.cpp (17) exprtk_simple_example_13.cpp (18) exprtk_simple_example_14.cpp +(19) exprtk_simple_example_15.cpp