ROUNDDOWN 関数の結果が Excel (2000以降)と異なる場合がある
対象製品
El Tabelle for .NET
詳細
小数点以下の値を含む計算を ROUNDDOWN 関数内で実行すると、ROUNDDOWN 関数の結果が Excel (2000以降)と異なるケースがあります。
具体的には
の結果が El Tabelle では 32639 ですが、Excel (2000以降)では 32640 です。
この現象は ROUNDDOWN 関数内で Double 型のデータで計算を行っていることによるもので、Double 型が小数点以下のデータを厳密に扱えない仕様に起因します。これは Excel 95/97 でも同様に確認できます。
El Tabelle と Excel で結果が異なるのは、Excel 2000 以降に ROUNDDOWN 関数に補正処理が組み込まれたためです。El Tabelle では関数内の処理を Decimal 型で行うことにより、Excel と同じ結果を得ることができます。
以下は ROUNDDOWN ユーザー定義関数を上書きするためのコードです。
[Visual Basic]
[C#]
以下は Decimal 型で処理を行う ROUNDDOWN ユーザー定義関数です。
[Visual Basic]
[C#]
なお、2003年12月22日以降のトライアル版、修正版にこのコードを使用したサンプルプロジェクトが含まれています。
具体的には
=ROUNDDOWN(800*40.8,0)
の結果が El Tabelle では 32639 ですが、Excel (2000以降)では 32640 です。
この現象は ROUNDDOWN 関数内で Double 型のデータで計算を行っていることによるもので、Double 型が小数点以下のデータを厳密に扱えない仕様に起因します。これは Excel 95/97 でも同様に確認できます。
El Tabelle と Excel で結果が異なるのは、Excel 2000 以降に ROUNDDOWN 関数に補正処理が組み込まれたためです。El Tabelle では関数内の処理を Decimal 型で行うことにより、Excel と同じ結果を得ることができます。
以下は ROUNDDOWN ユーザー定義関数を上書きするためのコードです。
[Visual Basic]
'ROUNDDOWNクラスからオブジェクトを作成する
Dim objRoundDown As ROUNDDOWN = New ROUNDDOWN()
'ユーザー定義関数のコレクションにオブジェクトを追加する
WorkBook1.CustomFunctions.Add(objRoundDown)
Dim objRoundDown As ROUNDDOWN = New ROUNDDOWN()
'ユーザー定義関数のコレクションにオブジェクトを追加する
WorkBook1.CustomFunctions.Add(objRoundDown)
[C#]
//ROUNDDOWNクラスからオブジェクトを作成する
ROUNDDOWN objRoundDown = new ROUNDDOWN();
//ユーザー定義関数のコレクションにオブジェクトを追加する
workBook1.CustomFunctions.Add(objRoundDown);
ROUNDDOWN objRoundDown = new ROUNDDOWN();
//ユーザー定義関数のコレクションにオブジェクトを追加する
workBook1.CustomFunctions.Add(objRoundDown);
以下は Decimal 型で処理を行う ROUNDDOWN ユーザー定義関数です。
[Visual Basic]
Imports GrapeCity.Data.FormulaService
'ROUNDDOWN関数のDecimal対応版
Public Class ROUNDDOWN
Implements ICustomFunction
Private m_ErrorMessage As String = Nothing
Private m_hasError As Boolean = False
Public ReadOnly Property Name() As String Implements ICustomFunction.Name
Get
'関数の名前
Return "ROUNDDOWN"
End Get
End Property
Public ReadOnly Property Description() As String Implements ICustomFunction.Description
Get
'関数の説明
Return "Rounds a number down, toward zero."
End Get
End Property
Public ReadOnly Property ErrorMessage() As String Implements ICustomFunction.ErrorMessage
Get
'エラーメッセージ
Return m_ErrorMessage
End Get
End Property
Public ReadOnly Property HasError() As Boolean Implements ICustomFunction.HasError
Get
'エラーの有無
Return m_hasError
End Get
End Property
Public Function Calculate(ByVal ParamArray List() As Object) As Object Implements ICustomFunction.Calculate
'計算処理
Dim i As Integer
m_hasError = False
If List.Length = 2 Then
Dim mid1 As Decimal
Dim result As Decimal
If List(1) Is System.DBNull.Value Then
mid1 = 0
Else
mid1 = CDec(List(1))
End If
If List(1) < 16 Then
Dim test As Decimal = Math.Pow(10, mid1)
Dim test1 As Decimal = CDec(List(0) * test)
If test1 < Decimal.MaxValue And test1 > Decimal.MinValue Then
Dim test2 As Decimal = test1
result = test2 / test
Else
result = List(0)
End If
Else
result = CDec(List(0))
End If
Return result
Else
m_ErrorMessage = "パラメータの数が不正です"
m_hasError = True
End If
Return Nothing
End Function
Public ReadOnly Property ParamType() As Type() Implements ICustomFunction.ParamType
Get
'関数のパラメータ
Return New Type() {GetType(Decimal), GetType(Integer)}
End Get
End Property
Public ReadOnly Property ReturnType() As Type Implements ICustomFunction.ReturnType
Get
'関数の戻り値
Return GetType(Decimal)
End Get
End Property
End Class
'ROUNDDOWN関数のDecimal対応版
Public Class ROUNDDOWN
Implements ICustomFunction
Private m_ErrorMessage As String = Nothing
Private m_hasError As Boolean = False
Public ReadOnly Property Name() As String Implements ICustomFunction.Name
Get
'関数の名前
Return "ROUNDDOWN"
End Get
End Property
Public ReadOnly Property Description() As String Implements ICustomFunction.Description
Get
'関数の説明
Return "Rounds a number down, toward zero."
End Get
End Property
Public ReadOnly Property ErrorMessage() As String Implements ICustomFunction.ErrorMessage
Get
'エラーメッセージ
Return m_ErrorMessage
End Get
End Property
Public ReadOnly Property HasError() As Boolean Implements ICustomFunction.HasError
Get
'エラーの有無
Return m_hasError
End Get
End Property
Public Function Calculate(ByVal ParamArray List() As Object) As Object Implements ICustomFunction.Calculate
'計算処理
Dim i As Integer
m_hasError = False
If List.Length = 2 Then
Dim mid1 As Decimal
Dim result As Decimal
If List(1) Is System.DBNull.Value Then
mid1 = 0
Else
mid1 = CDec(List(1))
End If
If List(1) < 16 Then
Dim test As Decimal = Math.Pow(10, mid1)
Dim test1 As Decimal = CDec(List(0) * test)
If test1 < Decimal.MaxValue And test1 > Decimal.MinValue Then
Dim test2 As Decimal = test1
result = test2 / test
Else
result = List(0)
End If
Else
result = CDec(List(0))
End If
Return result
Else
m_ErrorMessage = "パラメータの数が不正です"
m_hasError = True
End If
Return Nothing
End Function
Public ReadOnly Property ParamType() As Type() Implements ICustomFunction.ParamType
Get
'関数のパラメータ
Return New Type() {GetType(Decimal), GetType(Integer)}
End Get
End Property
Public ReadOnly Property ReturnType() As Type Implements ICustomFunction.ReturnType
Get
'関数の戻り値
Return GetType(Decimal)
End Get
End Property
End Class
[C#]
using GrapeCity.Win.ElTabelle;
namespace Rounddown
{
///
/// ROUNDDOWN関数のDecimal対応版
///
public class ROUNDDOWN : ICustomFunction
{
private string m_ErrorMessage = null;
private bool m_hasError = false;
public ROUNDDOWN()
{
//
// TODO: コンストラクタ ロジックをここに追加してください。
//
}
public string Name
{
get
{
//関数の名前
return "ROUNDDOWN";
}
}
public string Description
{
get
{
//関数の説明
return "Rounds a number down, toward zero.";
}
}
public string ErrorMessage
{
get
{
//エラーメッセージ
return m_ErrorMessage;
}
}
public bool HasError
{
get
{
//エラーの有無
return m_hasError;
}
}
public object Calculate (params object[] List)
{
//計算処理
m_hasError = false;
if (List.Length == 2)
{
decimal mid1;
decimal result;
if(List[1] == null)
{
mid1 = 0;
}
else
{
mid1 = (decimal)float.Parse(List[1].ToString());
}
if(((int)float.Parse(List[1].ToString())) < (int)16)
{
decimal test = (decimal)Math.Pow(10, (double)mid1);
decimal test1 = (decimal)float.Parse(List[0].ToString()) * test;
if((test1 < decimal.MaxValue) & (test1 > decimal.MinValue))
{
decimal test2 = test1;
result = test2 / test;
}
else
{
result = (decimal)List[0];
}
}
else
{
result = (decimal)List[0];
}
return result;
}
else
{
m_ErrorMessage = "パラメータの数が不正です";
m_hasError = true;
}
return null;
}
public Type[] ParamType
{
get
{
//関数のパラメータ
return new Type [] { typeof(double), typeof(double) };
}
}
public Type ReturnType
{
get
{
//関数の戻り値
return typeof(double);
}
}
}
}
namespace Rounddown
{
///
/// ROUNDDOWN関数のDecimal対応版
///
public class ROUNDDOWN : ICustomFunction
{
private string m_ErrorMessage = null;
private bool m_hasError = false;
public ROUNDDOWN()
{
//
// TODO: コンストラクタ ロジックをここに追加してください。
//
}
public string Name
{
get
{
//関数の名前
return "ROUNDDOWN";
}
}
public string Description
{
get
{
//関数の説明
return "Rounds a number down, toward zero.";
}
}
public string ErrorMessage
{
get
{
//エラーメッセージ
return m_ErrorMessage;
}
}
public bool HasError
{
get
{
//エラーの有無
return m_hasError;
}
}
public object Calculate (params object[] List)
{
//計算処理
m_hasError = false;
if (List.Length == 2)
{
decimal mid1;
decimal result;
if(List[1] == null)
{
mid1 = 0;
}
else
{
mid1 = (decimal)float.Parse(List[1].ToString());
}
if(((int)float.Parse(List[1].ToString())) < (int)16)
{
decimal test = (decimal)Math.Pow(10, (double)mid1);
decimal test1 = (decimal)float.Parse(List[0].ToString()) * test;
if((test1 < decimal.MaxValue) & (test1 > decimal.MinValue))
{
decimal test2 = test1;
result = test2 / test;
}
else
{
result = (decimal)List[0];
}
}
else
{
result = (decimal)List[0];
}
return result;
}
else
{
m_ErrorMessage = "パラメータの数が不正です";
m_hasError = true;
}
return null;
}
public Type[] ParamType
{
get
{
//関数のパラメータ
return new Type [] { typeof(double), typeof(double) };
}
}
public Type ReturnType
{
get
{
//関数の戻り値
return typeof(double);
}
}
}
}
なお、2003年12月22日以降のトライアル版、修正版にこのコードを使用したサンプルプロジェクトが含まれています。
キーワード
機能・仕様
この文書は、以前は次のFAQ IDで公開されていました : 3660