Poco::FPEnvironment

Poco::FPEnvironment を紹介します。

このクラスは Rounding Mode と浮動小数点フラグからなる浮動小数点環境を Save/Restore するのに使えます。また、浮動小数点数のプロパティを問い合わせる幾つかのスタティックメソッドも提供しています。

FPEnvironmentTest.cpp

・TestClassify() で、isNaN()isInfinite() を float, double について
 チェック。
・TestFlags() で isFlag() を呼んで、FP_DIVIDE_BY_ZERO, FP_OVERFLOW, FP_UNDERFLOW について
 チェック。
 (Linux 環境では、なぜか underflow のフラグが意図した通りに出ないので、while ループで強引に
  underflow に持ち込んでいる。なぜそうなるのか分かる方がおられましたら教えてください。)
・TestRound() で、Poco::FPEnvironment のインスタンス化前後で浮動小数点環境が Save/Restore される
 かどうかをチェック。

#include <Poco/Format.h>
#include <Poco/FPEnvironment.h>
 
#include <string>
 
#include "ScopedLogMessage.h"
#include "PrepareConsoleLogger.h"
 
std::string GetBoolString(bool in)
{
	return std::string(in ? "true":"false");
}
 
template<class T>
void Classify(ScopedLogMessage& msg)
{
	T a = 0.0;
	T b = 0.0;
	T nan = a/b;
	T inf = static_cast<T>(1.0)/b;
 
	msg.Message(Poco::format("  isNaN(0.0/0.0): %s",
			GetBoolString(Poco::FPE::isNaN(nan))));
	msg.Message(Poco::format("  isNaN(0.0): %s",
			GetBoolString(Poco::FPE::isNaN(a))));
	msg.Message(Poco::format("  isInfinite(1.0/0.0): %s",
			GetBoolString(Poco::FPE::isInfinite(inf))));
	msg.Message(Poco::format("  isInfinite(0.0): %s",
			GetBoolString(Poco::FPE::isInfinite(a))));
};
 
void TestClassify(ScopedLogMessage& msg)
{
	msg.Message(" --- float ---");
	Classify<float>(msg);
 
	msg.Message(" --- double ---");
	Classify<double>(msg);
}
 
#if defined(__HP_aCC)
#pragma OPTIMIZE OFF
#elif defined(_MSC_VER)
#pragma optimize("", off)
#endif
 
double mult(double a, double b)
{
	return a*b;
}
 
double div(double a, double b)
{
	return a/b;
}
 
void TestFlags(ScopedLogMessage& msg)
{
	Poco::FPE::clearFlags();
	msg.Message(" --- div(10, 0) ---");
	double a = 10;
	double b = 0;
	double c = div(a, b);
	msg.Message(Poco::format("  isFlag(Poco::FPE::FP_DIVIDE_BY_ZERO): %s",
			GetBoolString(Poco::FPE::isFlag(Poco::FPE::FP_DIVIDE_BY_ZERO))));
	msg.Message(Poco::format("  isInfinite: %s",
			GetBoolString(Poco::FPE::isInfinite(c))));
 
	Poco::FPE::clearFlags();
	a = 1.23456789e210;
	b = 9.87654321e210;
	c = mult(a, b);
	msg.Message(Poco::format(" --- mult(%1.8e, %1.8e) ---", a, b));
	msg.Message(Poco::format("  isFlag(Poco::FPE::FP_OVERFLOW): %s",
			GetBoolString(Poco::FPE::isFlag(Poco::FPE::FP_OVERFLOW))));
	msg.Message(Poco::format("  isInfinite: %s",
			GetBoolString(Poco::FPE::isInfinite(c))));
 
	Poco::FPE::clearFlags();
	a = 1.23456789e-99;
	b = 9.87654321e210;
	c = div(a, b);	
	while( !Poco::FPE::isFlag(Poco::FPE::FP_UNDERFLOW) )
	{
		Poco::FPE::clearFlags();
		a *= 0.1;
		b *= 10.0;
		c = div(a, b);	
	}
	msg.Message(Poco::format(" --- div(%1.8e, %1.8e) ---", a, b));
	msg.Message(Poco::format("  isFlag(Poco::FPE::FP_UNDERFLOW): %s",
			GetBoolString(Poco::FPE::isFlag(Poco::FPE::FP_UNDERFLOW))));
	msg.Message(Poco::format("  isInfinite: %s",
			GetBoolString(Poco::FPE::isInfinite(c))));
}
 
#if defined(__HP_aCC)
#pragma OPTIMIZE ON
#elif defined(_MSC_VER)
#pragma optimize("", on)
#endif
 
void TestRound(ScopedLogMessage& msg)
{
	#if !defined(__osf__) && !defined(__VMS)
	msg.Message(" --- RoundingMode ---");
	Poco::FPE::setRoundingMode(Poco::FPE::FP_ROUND_TONEAREST);			
	msg.Message(Poco::format("  getRoundingMode() == Poco::FPE::FP_ROUND_TONEAREST: %s",
			GetBoolString(Poco::FPE::getRoundingMode() == Poco::FPE::FP_ROUND_TONEAREST)));
	{
		Poco::FPE env(Poco::FPE::FP_ROUND_TOWARDZERO);
		msg.Message(Poco::format("  getRoundingMode() == Poco::FPE::FP_ROUND_TOWARDZERO: %s",
			GetBoolString(Poco::FPE::getRoundingMode() == Poco::FPE::FP_ROUND_TOWARDZERO)));
	}
	msg.Message(Poco::format("  getRoundingMode() == Poco::FPE::FP_ROUND_TONEAREST: %s",
			GetBoolString(Poco::FPE::getRoundingMode() == Poco::FPE::FP_ROUND_TONEAREST)));
	#endif
}
 
int main(int /*argc*/, char** /*argv*/)
{
	PrepareConsoleLogger logger(Poco::Logger::ROOT, Poco::Message::PRIO_INFORMATION);
 
	ScopedLogMessage msg("FPEnvironmentTest ", "start", "end");
 
	TestClassify(msg);
	TestFlags(msg);
	TestRound(msg);
 
	return 0;
}

Results of execution

[0] FPEnvironmentTest start
[0]  --- float ---
[0]   isNaN(0.0/0.0): true
[0]   isNaN(0.0): false
[0]   isInfinite(1.0/0.0): true
[0]   isInfinite(0.0): false
[0]  --- double ---
[0]   isNaN(0.0/0.0): true
[0]   isNaN(0.0): false
[0]   isInfinite(1.0/0.0): true
[0]   isInfinite(0.0): false
[0]  --- div(10, 0) ---
[0]   isFlag(Poco::FPE::FP_DIVIDE_BY_ZERO): true
[0]   isInfinite: true
[0]  --- mult(1.23456789e+210, 9.87654321e+210) ---
[0]   isFlag(Poco::FPE::FP_OVERFLOW): true
[0]   isInfinite: true
[0]  --- div(1.23456789e-99, 9.87654321e+210) ---
[0]   isFlag(Poco::FPE::FP_UNDERFLOW): true
[0]   isInfinite: false
[0]  --- RoundingMode ---
[0]   getRoundingMode() == Poco::FPE::FP_ROUND_TONEAREST: true
[0]   getRoundingMode() == Poco::FPE::FP_ROUND_TOWARDZERO: true
[0]   getRoundingMode() == Poco::FPE::FP_ROUND_TONEAREST: true
[0] FPEnvironmentTest end

Downloads

ここをクリックすると、makefile や VC++ プロジェクトなど一式がダウンロードできます。
(2013.05.31 updated)
・2010年7月23日からのダウンロード数:740

Subversion

・フリーの Subversion ホスティングサービス Assemblaで、ソースコードを管理しています。

Powered by POCO Copyright © 2010 Round Square Inc. All rights reserved.


Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>