ROUNDDOWN 関数の結果が Excel (2000以降)と異なる場合がある
対象製品
El Tabelle for .NET 3.0J
詳細
WorkBook/Sheet コントロールの数式機能において、小数点以下の値を含む計算を 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#]
なお、製品に付属のサンプル(製品インストールフォルダ¥Samples¥WorkBookSheet 内)にこのコードを使用したサンプルプロジェクト「Rounddown」が含まれています。
具体的には
=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);
}
}
}
}
なお、製品に付属のサンプル(製品インストールフォルダ¥Samples¥WorkBookSheet 内)にこのコードを使用したサンプルプロジェクト「Rounddown」が含まれています。
キーワード
問題
この文書は、以前は次のFAQ IDで公開されていました : 6899