/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifdef _MSC_VER
#pragma hdrstop
#endif

#include <string.h>

#include <bf_svtools/zforlist.hxx>

#include "interpre.hxx"
#include "dociter.hxx"
#include "scmatrix.hxx"
#include "globstr.hrc"
namespace binfilter {

// STATIC DATA -----------------------------------------------------------

#define SCdEpsilon                1.0E-7


// -----------------------------------------------------------------------

double ScInterpreter::ScGetGGT(double fx, double fy)
{
    if (fy == 0.0 || fx == 0.0)
    {
        SetError(errIllegalArgument);
        return 1.0;
    }
    else
    {
        double fz = fmod(fx, fy);
        while (fz > 0.0)
        {
            fx = fy;
            fy = fz;
            fz = fmod(fx, fy);
        }
        return fy;
    }
}

void ScInterpreter::ScGGT()
{
    BYTE nParamCount = GetByte();
    if ( MustHaveParamCountMin( nParamCount, 1 ) )
    {
        double fSign = 1.0;
        double fx, fy = 0.0;
        switch (GetStackType())
        {
            case svDouble :
            case svString:
            case svSingleRef:
            {
                fy = GetDouble();
                if (fy < 0.0)
                {
                    fy *= -1.0;
                    fSign *= -1.0;
                }
            }
            break;
            case svDoubleRef :
            {
                ScRange aRange;
                USHORT nErr = 0;
                PopDoubleRef( aRange );
                double nCellVal;
                ScValueIterator aValIter(pDok, aRange, glSubTotal);
                if (aValIter.GetFirst(nCellVal, nErr))
                {
                    fy = nCellVal;
                    if (fy < 0.0)
                    {
                        fy *= -1.0;
                        fSign *= -1.0;
                    }
                    while (nErr == 0 && aValIter.GetNext(nCellVal, nErr))
                    {
                        fx = nCellVal;
                        if (fx < 0.0)
                        {
                            fx *= -1.0;
                            fSign *= -1.0;
                        }
                        fy = ScGetGGT(fx, fy);
                    }
                    SetError(nErr);
                }
                else
                    SetError(errIllegalArgument);
            }
            break;
            case svMatrix :
            {
                ScMatrix* pMat = PopMatrix();
                if (pMat)
                {
                    USHORT nC, nR;
                    pMat->GetDimensions(nC, nR);
                    if (nC == 0 || nR == 0)
                        SetError(errIllegalArgument);
                    else
                    {
                        if (!pMat->IsValue(0))
                        {
                            SetIllegalArgument();
                            return;
                        }
                        fy = pMat->GetDouble(0);
                        if (fy < 0.0)
                        {
                            fy *= -1.0;
                            fSign *= -1.0;
                        }
                        ULONG nCount = (ULONG) nC * nR;
                        for ( ULONG j = 1; j < nCount; j++ )
                        {
                            if (!pMat->IsValue(j))
                            {
                                SetIllegalArgument();
                                return;
                            }
                            fx = pMat->GetDouble(j);
                            if (fx < 0.0)
                            {
                                fx *= -1.0;
                                fSign *= -1.0;
                            }
                            fy = ScGetGGT(fx, fy);
                        }
                    }
                }
            }
            break;
            default : SetError(errIllegalParameter); break;
        }
        ScRange aRange;
        for (short i = 0; i < (short) nParamCount - 1; i++)
        {
            switch (GetStackType())
            {
                case svDouble :
                case svString:
                case svSingleRef:
                {
                    fx = GetDouble();
                    if (fx < 0.0)
                    {
                        fx *= -1.0;
                        fSign *= -1.0;
                    }
                    fy = ScGetGGT(fx, fy);
                }
                break;
                case svDoubleRef :
                {
                    USHORT nErr = 0;
                    PopDoubleRef( aRange );
                    double nCellVal;
                    ScValueIterator aValIter(pDok, aRange, glSubTotal);
                    if (aValIter.GetFirst(nCellVal, nErr))
                    {
                        fx = nCellVal;
                        if (fx < 0.0)
                        {
                            fx *= -1.0;
                            fSign *= -1.0;
                        }
                        fy = ScGetGGT(fx, fy);
                        while (nErr == 0 && aValIter.GetNext(nCellVal, nErr))
                        {
                            fx = nCellVal;
                            if (fx < 0.0)
                            {
                                fx *= -1.0;
                                fSign *= -1.0;
                            }
                            fy = ScGetGGT(fx, fy);
                        }
                        SetError(nErr);
                    }
                    else
                        SetError(errIllegalArgument);
                }
                break;
                case svMatrix :
                {
                    ScMatrix* pMat = PopMatrix();
                    if (pMat)
                    {
                        USHORT nC, nR;
                        pMat->GetDimensions(nC, nR);
                        if (nC == 0 || nR == 0)
                            SetError(errIllegalArgument);
                        else
                        {
                            if (!pMat->IsValue(0))
                            {
                                SetIllegalArgument();
                                return;
                            }
                            fx = pMat->GetDouble(0);
                            if (fx < 0.0)
                            {
                                fx *= -1.0;
                                fSign *= -1.0;
                            }
                            fy = ScGetGGT(fx, fy);
                            ULONG nCount = (ULONG) nC * nR;
                            for ( ULONG j = 1; j < nCount; j++ )
                            {
                                if (!pMat->IsValue(j))
                                {
                                    SetIllegalArgument();
                                    return;
                                }
                                fx = pMat->GetDouble(j);
                                if (fx < 0.0)
                                {
                                    fx *= -1.0;
                                    fSign *= -1.0;
                                }
                                fy = ScGetGGT(fx, fy);
                            }
                        }
                    }
                }
                break;
                default : SetError(errIllegalParameter); break;
            }
        }
        if (fSign == -1.0)
            PushDouble(-fy);
        else
            PushDouble(fy);
    }
}

void ScInterpreter:: ScKGV()
{
    BYTE nParamCount = GetByte();
    if ( MustHaveParamCountMin( nParamCount, 1 ) )
    {
        double fSign = 1.0;
        double fx, fy = 0.0;
        switch (GetStackType())
        {
            case svDouble :
            case svString:
            case svSingleRef:
            {
                fy = GetDouble();
                if (fy < 0.0)
                {
                    fy *= -1.0;
                    fSign *= -1.0;
                }
            }
            break;
            case svDoubleRef :
            {
                ScRange aRange;
                USHORT nErr = 0;
                PopDoubleRef( aRange );
                double nCellVal;
                ScValueIterator aValIter(pDok, aRange, glSubTotal);
                if (aValIter.GetFirst(nCellVal, nErr))
                {
                    fy = nCellVal;
                    if (fy < 0.0)
                    {
                        fy *= -1.0;
                        fSign *= -1.0;
                    }
                    while (nErr == 0 && aValIter.GetNext(nCellVal, nErr))
                    {
                        fx = nCellVal;
                        if (fx < 0.0)
                        {
                            fx *= -1.0;
                            fSign *= -1.0;
                        }
                        fy = fx * fy / ScGetGGT(fx, fy);
                    }
                    SetError(nErr);
                }
                else
                    SetError(errIllegalArgument);
            }
            break;
            case svMatrix :
            {
                ScMatrix* pMat = PopMatrix();
                if (pMat)
                {
                    USHORT nC, nR;
                    pMat->GetDimensions(nC, nR);
                    if (nC == 0 || nR == 0)
                        SetError(errIllegalArgument);
                    else
                    {
                        if (!pMat->IsValue(0))
                        {
                            SetIllegalArgument();
                            return;
                        }
                        fy = pMat->GetDouble(0);
                        if (fy < 0.0)
                        {
                            fy *= -1.0;
                            fSign *= -1.0;
                        }
                        ULONG nCount = (ULONG) nC * nR;
                        for ( ULONG j = 1; j < nCount; j++ )
                        {
                            if (!pMat->IsValue(j))
                            {
                                SetIllegalArgument();
                                return;
                            }
                            fx = pMat->GetDouble(j);
                            if (fx < 0.0)
                            {
                                fx *= -1.0;
                                fSign *= -1.0;
                            }
                            fy = fx * fy / ScGetGGT(fx, fy);
                        }
                    }
                }
            }
            break;
            default : SetError(errIllegalParameter); break;
        }
        ScRange aRange;
        for (short i = 0; i < (short) nParamCount - 1; i++)
        {
            switch (GetStackType())
            {
                case svDouble :
                case svString:
                case svSingleRef:
                {
                    fx = GetDouble();
                    if (fx < 0.0)
                    {
                        fx *= -1.0;
                        fSign *= -1.0;
                    }
                    fy = fx * fy / ScGetGGT(fx, fy);
                }
                break;
                case svDoubleRef :
                {
                    USHORT nErr = 0;
                    PopDoubleRef( aRange );
                    double nCellVal;
                    ScValueIterator aValIter(pDok, aRange, glSubTotal);
                    if (aValIter.GetFirst(nCellVal, nErr))
                    {
                        fx = nCellVal;
                        if (fx < 0.0)
                        {
                            fx *= -1.0;
                            fSign *= -1.0;
                        }
                        fy = fx * fy / ScGetGGT(fx, fy);
                        while (nErr == 0 && aValIter.GetNext(nCellVal, nErr))
                        {
                            fx = nCellVal;
                            if (fx < 0.0)
                            {
                                fx *= -1.0;
                                fSign *= -1.0;
                            }
                            fy = fx * fy / ScGetGGT(fx, fy);
                        }
                        SetError(nErr);
                    }
                    else
                        SetError(errIllegalArgument);
                }
                break;
                case svMatrix :
                {
                    ScMatrix* pMat = PopMatrix();
                    if (pMat)
                    {
                        USHORT nC, nR;
                        pMat->GetDimensions(nC, nR);
                        if (nC == 0 || nR == 0)
                            SetError(errIllegalArgument);
                        else
                        {
                            if (!pMat->IsValue(0))
                            {
                                SetIllegalArgument();
                                return;
                            }
                            fx = pMat->GetDouble(0);
                            if (fx < 0.0)
                            {
                                fx *= -1.0;
                                fSign *= -1.0;
                            }
                            fy = fx * fy / ScGetGGT(fx, fy);
                            ULONG nCount = (ULONG) nC * nR;
                            for ( ULONG j = 1; j < nCount; j++ )
                            {
                                if (!pMat->IsValue(j))
                                {
                                    SetIllegalArgument();
                                    return;
                                }
                                fx = pMat->GetDouble(j);
                                if (fx < 0.0)
                                {
                                    fx *= -1.0;
                                    fSign *= -1.0;
                                }
                                fy = fx * fy / ScGetGGT(fx, fy);
                            }
                        }
                    }
                }
                break;
                default : SetError(errIllegalParameter); break;
            }
        }
        if (fSign == -1.0)
            PushDouble(-fy);
        else
            PushDouble(fy);
    }
}

/*N*/ ScMatrix* ScInterpreter::GetNewMat(USHORT nC, USHORT nR, USHORT& nMatInd)
/*N*/ {
/*N*/ 	if (nMatCount == MAX_ANZ_MAT)
/*N*/ 	{
/*N*/ 		DBG_ERROR("ScInterpreter::GetNewMat: Matrixueberlauf");
/*N*/ 		SetError(errCodeOverflow);
/*N*/ 		nMatInd = MAX_ANZ_MAT;
/*N*/ 		return NULL;
/*N*/ 	}
/*N*/ 	else
/*N*/ 	{
/*N*/ 		if (!bMatDel)								// beim ersten Mal
/*N*/ 		{
/*N*/ 			ppTempMatArray = new ScMatrix* [MAX_ANZ_MAT];
/*N*/ 			for (USHORT i = 0; i < MAX_ANZ_MAT; i++)
/*N*/ 				ppTempMatArray[i] = NULL;
/*N*/ 			bMatDel = TRUE;
/*N*/ 		}
/*N*/ 		ppTempMatArray[nMatCount] = new ScMatrix(nC, nR);
/*N*/ 		nMatInd = nMatCount++;
/*N*/ 		return ppTempMatArray[nMatInd];
/*N*/ 	}
/*N*/ }

/*N*/ void ScInterpreter::ResetNewMat(USHORT nIndex)
/*N*/ {
/*N*/ 	if (nIndex < MAX_ANZ_MAT)
/*N*/ 	{
/*N*/ 		ppTempMatArray[nIndex] = NULL;
/*N*/ 		if (nIndex == nMatCount - 1)
/*N*/ 			nMatCount--;
/*N*/ 	}
/*N*/ }

/*N*/ ScMatrix* ScInterpreter::GetMatrix(USHORT& nMatInd)
/*N*/ {
/*N*/ 	ScMatrix* pMat = NULL;
/*N*/ 	switch (GetStackType())
/*N*/ 	{
/*?*/ 		case svSingleRef :
/*?*/ 		{
/*?*/ 			ScAddress aAdr;
/*?*/ 			PopSingleRef( aAdr );
/*?*/ 			pMat = GetNewMat(1, 1, nMatInd);
/*?*/ 			if (pMat)
/*?*/ 			{
/*?*/ 				ScBaseCell* pCell = GetCell( aAdr );
/*?*/ 				if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE )
/*?*/ 				{
/*?*/ 					if (HasCellValueData(pCell))
/*?*/                         pMat->PutDouble(GetCellValue(aAdr, pCell), 0);
/*?*/ 					else
/*?*/ 					{
/*?*/ 						String aStr;
/*?*/ 						GetCellString(aStr, pCell);
/*?*/                         pMat->PutString(aStr, 0);
/*?*/ 					}
/*?*/ 				}
/*?*/ 				else
/*?*/                     pMat->PutEmpty( 0 );
/*?*/ 			}
/*?*/ 			else
/*?*/ 				SetError(errCodeOverflow);
/*?*/ 		}
/*?*/ 		break;
/*N*/ 		case svDoubleRef:
/*N*/ 		{
/*N*/ 			USHORT nCol1, nRow1, nTab1, nCol2, nRow2, nTab2;
/*N*/ 			PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
/*N*/ 			if (nTab1 == nTab2)
/*N*/ 			{
/*N*/ 				USHORT i, j;
/*N*/ 				if ( (ULONG) (nRow2 - nRow1 + 1) * (nCol2 - nCol1 + 1) >
/*N*/ 						ScMatrix::GetElementsMax() )
/*N*/ 					SetError(errStackOverflow);
/*N*/ 				else
/*N*/ 				{
/*N*/ 					pMat = GetNewMat(nCol2 - nCol1 + 1, nRow2 - nRow1 + 1, nMatInd);
/*N*/ 					if (pMat)
/*N*/ 					{
/*N*/ 						ScAddress aAdr( nCol1, nRow1, nTab1 );
/*N*/ 						for (i = nRow1; i <= nRow2; i++)
/*N*/ 						{
/*N*/ 							aAdr.SetRow( i );
/*N*/ 							for (j = nCol1; j <= nCol2; j++)
/*N*/ 							{
/*N*/ 								aAdr.SetCol( j );
/*N*/ 								ScBaseCell* pCell = GetCell( aAdr );
/*N*/ 								if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE )
/*N*/ 								{
/*N*/ 									if (HasCellValueData(pCell))
/*N*/ 										pMat->PutDouble(
/*N*/ 												GetCellValue( aAdr, pCell ),
/*N*/ 												j-nCol1, i-nRow1);
/*N*/ 									else
/*N*/ 									{
/*?*/ 										String aStr;
/*?*/ 										GetCellString(aStr, pCell);
/*?*/ 										pMat->PutString(aStr, j-nCol1, i-nRow1);
/*N*/ 									}
/*N*/ 								}
/*N*/ 								else
/*?*/ 									pMat->PutEmpty( j-nCol1, i-nRow1 );
/*N*/ 							}
/*N*/ 						}
/*N*/ 					}
/*N*/ 					else
/*N*/ 						SetError(errCodeOverflow);
/*N*/ 				}
/*N*/ 			}
/*N*/ 			else								// keine 2D-Matrix
/*N*/ 			{
/*N*/ 				nMatInd = MAX_ANZ_MAT;
/*N*/ 				SetError(errIllegalParameter);
/*N*/ 			}
/*N*/ 		}
/*N*/ 		break;
/*N*/ 		case svMatrix:
/*N*/ 			pMat = PopMatrix();
/*N*/ 			nMatInd = MAX_ANZ_MAT;
/*N*/ 		break;
/*?*/ 		default:
/*?*/ 			Pop();
/*?*/ 			nMatInd = MAX_ANZ_MAT;
/*?*/ 			SetError(errIllegalParameter);
/*?*/ 		break;
/*N*/ 	}
/*N*/ 	return pMat;
/*N*/ }

void ScInterpreter::ScMatValue()
{
    if ( MustHaveParamCount( GetByte(), 3 ) )
    {
        USHORT nR = (USHORT) ::rtl::math::approxFloor(GetDouble());		// 0 bis nAnz - 1
        USHORT nC = (USHORT) ::rtl::math::approxFloor(GetDouble());		// 0 bis nAnz - 1
        switch (GetStackType())
        {
            case svSingleRef :
            {
                ScAddress aAdr;
                PopSingleRef( aAdr );
                ScBaseCell* pCell = GetCell( aAdr );
                if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
                {
                    USHORT nErrCode = ((ScFormulaCell*)pCell)->GetErrCode();
                    if (nErrCode != 0)
                    {
                        SetError(nErrCode);
                        PushInt(0);
                    }
                    else
                    {
                        ScMatrix* pMat;
                        ((ScFormulaCell*)pCell)->GetMatrix(&pMat);
                        if (pMat)
                        {
                            USHORT nCl, nRw;
                            pMat->GetDimensions(nCl, nRw);
                            if (nC < nCl && nR < nRw)
                            {
                                BOOL bIsString;
                                const MatValue* pMatVal = pMat->Get(nC, nR, bIsString);
                                if (bIsString)
                                    PushString( pMatVal->GetString() );
                                else
                                    PushDouble(pMatVal->fVal);
                            }
                            else
                                SetNoValue();
                        }
                        else
                            SetNoValue();
                    }
                }
                else
                    SetIllegalParameter();
            }
            break;
            case svDoubleRef :
            {
                USHORT nCol1, nRow1, nTab1, nCol2, nRow2, nTab2;
                PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
                if (nCol2 - nCol1 >= nR && nRow2 - nRow1 >= nC && nTab1 == nTab2)
                {
                    ScAddress aAdr( nCol1 + nR, nRow1 + nC, nTab1 );
                    ScBaseCell* pCell = GetCell( aAdr );
                    if (HasCellValueData(pCell))
                        PushDouble(GetCellValue( aAdr, pCell ));
                    else
                    {
                        String aStr;
                        GetCellString(aStr, pCell);
                        PushString(aStr);
                    }
                }
                else
                    SetNoValue();
            }
            break;
            case svMatrix:
            {
                ScMatrix* pMat = PopMatrix();
                if (pMat)
                {
                    USHORT nCl, nRw;
                    pMat->GetDimensions(nCl, nRw);
                    if (nC < nCl && nR < nRw)
                    {
                        BOOL bIsString;
                        const MatValue* pMatVal = pMat->Get(nC, nR, bIsString);
                        if (bIsString)
                            PushString( pMatVal->GetString() );
                        else
                            PushDouble(pMatVal->fVal);
                    }
                    else
                        SetNoValue();
                }
                else
                    SetNoValue();
            }
            break;
            default:
                Pop();
                SetIllegalParameter();
            break;
        }
    }
}

void ScInterpreter::ScEMat()
{
    if ( MustHaveParamCount( GetByte(), 1 ) )
    {
        ULONG nDim = (ULONG) ::rtl::math::approxFloor(GetDouble());
        if ( nDim * nDim > ScMatrix::GetElementsMax() || nDim == 0)
            SetIllegalArgument();
        else
        {
            USHORT nMatInd;
            ScMatrix* pRMat = GetNewMat((USHORT)nDim, (USHORT)nDim, nMatInd);
            if (pRMat)
            {
                MEMat(pRMat, (USHORT) nDim);
                nRetMat = nMatInd;
                PushMatrix(pRMat);
            }
            else
                SetError(errStackOverflow);
        }
    }
}

void ScInterpreter::MEMat(ScMatrix* mM, USHORT n)
{
    mM->FillDouble(0.0, 0, 0, n-1, n-1);
    for (USHORT i = 0; i < n; i++)
        mM->PutDouble(1.0, i, i);
}

void ScInterpreter::MFastMult(ScMatrix* pA, ScMatrix* pB, ScMatrix* pR,
                              USHORT n, USHORT m, USHORT l)
        // Multipliziert n x m Mat a mit m x l Mat b nach Mat r
{
    double sum;
    for (USHORT i = 0; i < n; i++)
    {
        for (USHORT j = 0; j < l; j++)
        {
            sum = 0.0;
            for (USHORT k = 0; k < m; k++)
                sum += pA->GetDouble(i,k)*pB->GetDouble(k,j);
            pR->PutDouble(sum, i, j);
        }
    }
}

void ScInterpreter::MFastSub(ScMatrix* pA, ScMatrix* pB, ScMatrix* pR,
                              USHORT n, USHORT m)
        // Subtrahiert n x m Mat a - m x l Mat b nach Mat r
{
    for (USHORT i = 0; i < n; i++)
    {
        for (USHORT j = 0; j < m; j++)
            pR->PutDouble(pA->GetDouble(i,j) - pB->GetDouble(i,j), i, j);
    }
}

void ScInterpreter::MFastTrans(ScMatrix* pA, ScMatrix* pR,
                              USHORT n, USHORT m)
        // Transponiert n x m Mat a nach Mat r
{
    for (USHORT i = 0; i < n; i++)
        for (USHORT j = 0; j < m; j++)
            pR->PutDouble(pA->GetDouble(i, j), j, i);
}

BOOL ScInterpreter::MFastBackSubst(ScMatrix* pA, ScMatrix* pR, USHORT n, BOOL bIsUpper)
        // Führt Rückwaertsersetzung der Dreickesmatrix Mat a nach Mat r durch
        // 2 Versionen fuer obere (U)  oder untere (L- Unit) Dreiecksmatrizen
{
    short i, j, k;
    double fSum;
    if (!bIsUpper)							// L-Matrix, immer invertierbar
    {
        MEMat(pR, n);
        for (i = 1; i < (short) n; i++)
        {
            for (j = 0; j < i; j++)
            {
                fSum = 0.0;
                for (k = 0; k < i; k++)
                    fSum += pA->GetDouble(i,k) * pR->GetDouble(k,j);
                pR->PutDouble(-fSum, i, j);
            }
        }
    }
    else									// U-Matrix
    {
        for (i = 0; i < (short) n; i++)							// Ist invertierbar?
            if (fabs(pA->GetDouble(i,i)) < SCdEpsilon)
                return FALSE;
        pR->FillDoubleLowerLeft(0.0, n-1);                      // untere Haelfte
        pR->PutDouble(1.0/pA->GetDouble(n-1, n-1), n-1, n-1);	// n-1, n-1
        for (i = (short) n-2; i >= 0; i--)
        {
            for (j = (short) n-1; j > i; j--)
            {
                fSum = 0.0;
                for (k = (short) n-1; k > i; k--)
                    fSum += pA->GetDouble(i, k) * pR->GetDouble(k, j);
                pR->PutDouble(-fSum/pA->GetDouble(i, i), i, j);
            }
            fSum = 0.0;											// Hauptdiagonale:
            for (k = (short) n-1; k > i; k--)
                fSum += pA->GetDouble(i, k) * pR->GetDouble(k, j);
            pR->PutDouble((1.0-fSum)/pA->GetDouble(i, i), i, i);
        }
    }
    return TRUE;
}

BOOL ScInterpreter::ScMatLUP(ScMatrix* mA, USHORT m, USHORT p,
                             ScMatrix* mL, ScMatrix* mU, ScMatrix* mP,
                             ULONG& rPermutCounter, BOOL& bIsInvertable)
    // Returnwert = False <=> Matrixarray voll
    // BIsInvertable = False: <= mA hat nicht Rang m
{
    USHORT nMatInd1, nMatInd2, nMatInd3, nMatInd4, nMatInd5;
    USHORT i, j;
    if (m == 1)
    {
        mL->PutDouble(1.0,0,0);
        for (j = 0; j < p; j++)
            if (fabs(mA->GetDouble(0, j)) >= SCdEpsilon)
                break;
        if (j == p)
        {
            bIsInvertable = FALSE;
            return TRUE;
        }
        MEMat(mP, p);
        if (j > 0 && j < p)
        {
            mP->PutDouble(0.0, 0, 0);
            mP->PutDouble(1.0, j, 0);
            mP->PutDouble(0.0, j, j);
            mP->PutDouble(1.0, 0, j);
            rPermutCounter++;
        }
        MFastMult(mA, mP, mU, m, p, p);
    }
    else
    {
        USHORT md2 = m/2;
        ScMatrix* mB = GetNewMat(md2, p, nMatInd1);
        ScMatrix* mC = GetNewMat(md2, p, nMatInd2);
        ScMatrix* mL1 = GetNewMat(md2, md2, nMatInd3);
        ScMatrix* mU1 = GetNewMat(md2, p, nMatInd4);
        ScMatrix* mP1 = GetNewMat(p, p, nMatInd5);
        if (!mB || !mC || !mL1 || !mU1 || !mP1 )
            return FALSE;
        for (i = 0; i < md2; i++)
        {
            for (j = 0; j < p; j++)
            {
                mB->PutDouble(mA->GetDouble(i, j), i, j);
                mC->PutDouble(mA->GetDouble(md2+i,j), i, j);
            }
        }
        if (!ScMatLUP(mB, md2, p, mL1, mU1, mP1, rPermutCounter, bIsInvertable))
            return FALSE;
        if (!bIsInvertable)
        {
            ResetNewMat(nMatInd5);
            ResetNewMat(nMatInd4);
            ResetNewMat(nMatInd3);
            ResetNewMat(nMatInd2);
            ResetNewMat(nMatInd1);
            delete mP1;
            delete mU1;
            delete mL1;
            delete mC;
            delete mB;
            return TRUE;
        }
        USHORT nMatInd6, nMatInd7, nMatInd8, nMatInd9, nMatInd10;
        USHORT nMatInd11, nMatInd12, nMatInd13;
        ScMatrix* mE    = GetNewMat(md2, md2,         nMatInd6);
        ScMatrix* mF    = GetNewMat(md2, md2,         nMatInd7);
        ScMatrix* mEInv = GetNewMat(md2, md2,         nMatInd8);
        ScMatrix* mG    = GetNewMat(md2, p,           nMatInd9);
        ScMatrix* mGs   = GetNewMat(md2, p - md2,     nMatInd10);
        ScMatrix* mU2   = GetNewMat(md2, p - md2,     nMatInd11);
        ScMatrix* mP2   = GetNewMat(p - md2, p - md2, nMatInd12);
        if (!mP2 || !mU2 || !mGs|| !mG || !mEInv || !mF || !mE)
            return FALSE;
        MFastTrans(mP1, mP, p, p);				// mP = mP1 hoch  -1
        ScMatrix* mD = mB;						// mB wird nicht mehr gebraucht
        MFastMult(mC, mP, mD, md2, p, p);
        for (i = 0; i < md2; i++)
        {
            for (j = 0; j < md2; j++)
            {
                mE->PutDouble(mU1->GetDouble(i, j), i, j);
                mF->PutDouble(mD->GetDouble(i, j), i, j);
            }
        }
        BOOL bEInvok = MFastBackSubst(mE, mEInv, md2, TRUE); // MeInv = E hoch -1
        if (!bEInvok)
        {
            bIsInvertable = FALSE;
            ResetNewMat(nMatInd12);
            ResetNewMat(nMatInd11);
            ResetNewMat(nMatInd10);
            ResetNewMat(nMatInd9);
            ResetNewMat(nMatInd8);
            ResetNewMat(nMatInd7);
            ResetNewMat(nMatInd6);
            ResetNewMat(nMatInd5);
            ResetNewMat(nMatInd4);
            ResetNewMat(nMatInd3);
            ResetNewMat(nMatInd2);
            ResetNewMat(nMatInd1);
            delete mP2;
            delete mU2;
            delete mGs;
            delete mG;
            delete mEInv;
            delete mF;
            delete mE;
            delete mP1;
            delete mU1;
            delete mL1;
            delete mC;
            delete mB;
            return TRUE;
        }
        ScMatrix* mFEInv = mE;				// mE wird nicht mehr gebraucht.
        MFastMult(mF, mEInv, mFEInv, md2, md2, md2);
        ScMatrix* mFEInvU1 = mC;			// mC wird nicht mehr gebraucht
        MFastMult(mFEInv, mU1, mFEInvU1, md2, md2, p);
        MFastSub(mD, mFEInvU1, mG, md2, p);
        for (i = 0; i < md2; i++)
        {
            for (j = 0; j < p-md2; j++)
                mGs->PutDouble(mG->GetDouble(i, md2+j), i, j);
        }
        ScMatrix* mL2 = mF;					// mF wird nicht mehr gebraucht
        if (!ScMatLUP(mGs, md2, p - md2, mL2, mU2, mP2, rPermutCounter, bIsInvertable))
            return FALSE;
        if (!bIsInvertable)
        {
            ResetNewMat(nMatInd12);
            ResetNewMat(nMatInd11);
            ResetNewMat(nMatInd10);
            ResetNewMat(nMatInd9);
            ResetNewMat(nMatInd8);
            ResetNewMat(nMatInd7);
            ResetNewMat(nMatInd6);
            ResetNewMat(nMatInd5);
            ResetNewMat(nMatInd4);
            ResetNewMat(nMatInd3);
            ResetNewMat(nMatInd2);
            ResetNewMat(nMatInd1);
            delete mP2;
            delete mU2;
            delete mGs;
            delete mG;
            delete mEInv;
            delete mF;
            delete mE;
            delete mP1;
            delete mU1;
            delete mL1;
            delete mC;
            delete mB;
            return TRUE;
        }
        ScMatrix* mP3 =  GetNewMat(p, p, nMatInd13);
        if (!mP3)
            return FALSE;
        MEMat(mP3, p);
        for (i = md2; i < p; i++)
        {
            for (j = md2; j < p; j++)
                mP3->PutDouble(mP2->GetDouble(i-md2, j-md2), i, j);
        }
        MFastMult(mP3, mP1, mP, p, p, p);		// Ergebnis P !!
        ScMatrix* mP3Inv = mP1;					// mP1 wird nicht mehr gebraucht;
        MFastTrans(mP3, mP3Inv, p, p);
        ScMatrix* mH = mD;						// mD wird nicht mehr gebraucht
        MFastMult(mU1, mP3Inv, mH, md2, p, p);
        MEMat(mL, m);							// Ergebnis L :
        for (i = 0; i < md2; i++)
        {
            for (j = 0; j < i; j++)
                mL->PutDouble(mL1->GetDouble(i, j), i, j);
        }
        for (i = md2; i < m; i++)
            for (j = md2; j < i; j++)
                mL->PutDouble(mL2->GetDouble(i-md2, j-md2), i, j);
        for (i = md2; i < m; i++)
            for (j = 0; j < md2; j++)
                mL->PutDouble(mFEInv->GetDouble(i-md2, j), i, j);
                                                // Ergebnis U:
        mU->FillDoubleLowerLeft(0.0, m-1);
        for (i = 0; i < md2; i++)
            for (j = i; j < p; j++)
                mU->PutDouble(mH->GetDouble(i, j), i, j);
        for (i = md2; i < m; i++)
            for (j = i; j < p; j++)
                mU->PutDouble(mU2->GetDouble(i - md2, j - md2), i, j);
        ResetNewMat(nMatInd13);				// alle wieder freigeben;
        ResetNewMat(nMatInd12);
        ResetNewMat(nMatInd11);
        ResetNewMat(nMatInd10);
        ResetNewMat(nMatInd9);
        ResetNewMat(nMatInd8);
        ResetNewMat(nMatInd7);
        ResetNewMat(nMatInd6);
        ResetNewMat(nMatInd5);
        ResetNewMat(nMatInd4);
        ResetNewMat(nMatInd3);
        ResetNewMat(nMatInd2);
        ResetNewMat(nMatInd1);
        delete mP3;
        delete mP2;
        delete mU2;
        delete mGs;
        delete mG;
        delete mEInv;
        delete mF;
        delete mE;
        delete mP1;
        delete mU1;
        delete mL1;
        delete mC;
        delete mB;
    }
    return TRUE;
}

void ScInterpreter::ScMatDet()
{
    if ( MustHaveParamCount( GetByte(), 1 ) )
    {
        USHORT nMatInd;
        ScMatrix* pMat = GetMatrix(nMatInd);
        if (!pMat)
        {
            SetIllegalParameter();
            return;
        }
        if ( !pMat->IsNumeric() )
        {
            SetNoValue();
            return;
        }
        USHORT nC, nR;
        pMat->GetDimensions(nC, nR);
        if ( nC != nR || nC == 0 || (ULONG) nC * nC > ScMatrix::GetElementsMax() )
            SetIllegalParameter();
        else
        {
            double fVal = log((double)nC) / log(2.0);
            if (fVal - floor(fVal) != 0.0)
                fVal = floor(fVal) + 1.0;
            USHORT nDim = (USHORT) pow(2.0, fVal);
            USHORT nMatInd1, nMatInd2, nMatInd3;
            USHORT nMatInd4 = MAX_ANZ_MAT;
            ScMatrix* pU = GetNewMat(nDim, nDim, nMatInd1);
            ScMatrix* pL = GetNewMat(nDim, nDim, nMatInd2);
            ScMatrix* pP = GetNewMat(nDim, nDim, nMatInd3);
            ScMatrix* pA;
            if (nC == nDim)
                pA = pMat;
            else
            {
                pA = GetNewMat(nDim, nDim, nMatInd4);
                MEMat(pA, nDim);
                for (USHORT i = 0; i < nC; i++)
                    for (USHORT j = 0; j < nC; j++)
                    {
                        pA->PutDouble(pMat->GetDouble(i, j), i, j);
                    }
            }
            ULONG nPermutCounter = 0;
            BOOL bIsInvertable = TRUE;
            BOOL bOk = ScMatLUP(pA, nDim, nDim, pL, pU, pP,
                                nPermutCounter, bIsInvertable);
            ResetNewMat(nMatInd4);
            ResetNewMat(nMatInd3);
            ResetNewMat(nMatInd2);
            if (nC != nDim)
                delete pA;
            delete pP;
            delete pL;
            if (bOk)
            {
                if (!bIsInvertable)
                    PushInt(0);
                else
                {
                    double fDet = 1.0;
                    for (USHORT i = 0; i < nC; i++)
                        fDet *= pU->GetDouble(i, i);
                    if (nPermutCounter % 2 != 0)
                        fDet *= -1.0;
                    PushDouble(fDet);
                }
            }
            else
            {
                SetError(errCodeOverflow);
                PushInt(0);
            }
            ResetNewMat(nMatInd1);
            delete pU;
        }
    }
}

void ScInterpreter::ScMatInv()
{
    if ( MustHaveParamCount( GetByte(), 1 ) )
    {
        USHORT nMatInd;
        ScMatrix* pMat = GetMatrix(nMatInd);
        if (!pMat)
        {
            SetIllegalParameter();
            return;
        }
        if ( !pMat->IsNumeric() )
        {
            SetNoValue();
            return;
        }
        USHORT nC, nR;
        pMat->GetDimensions(nC, nR);
        if ( nC != nR || nC == 0 || (ULONG) nC * nC > ScMatrix::GetElementsMax() )
            SetIllegalParameter();
        else
        {
            double fVal = log((double)nC) / log(2.0);
            if (fVal - floor(fVal) != 0.0)
                fVal = floor(fVal) + 1.0;
            USHORT nDim = (USHORT) pow(2.0, fVal);
            USHORT nMatInd1, nMatInd2, nMatInd3;
            USHORT nMatInd4 = MAX_ANZ_MAT;
            ScMatrix* pU = GetNewMat(nDim, nDim, nMatInd1);
            ScMatrix* pL = GetNewMat(nDim, nDim, nMatInd2);
            ScMatrix* pP = GetNewMat(nDim, nDim, nMatInd3);
            ScMatrix* pA;
            if (nC == nDim)
                pA = pMat;
            else
            {
                pA = GetNewMat(nDim, nDim, nMatInd4);
                MEMat(pA, nDim);
                for (USHORT i = 0; i < nC; i++)
                    for (USHORT j = 0; j < nC; j++)
                    {
                        pA->PutDouble(pMat->GetDouble(i, j), i, j);
                    }
            }
            ULONG nPermutCounter = 0;
            BOOL bIsInvertable = TRUE;
            BOOL bOk = ScMatLUP(pA, nDim, nDim, pL, pU, pP,
                                nPermutCounter, bIsInvertable);
            if (bOk)
            {
                if (!bIsInvertable)
                    SetNoValue();
                else
                {
                    USHORT nMatInd5;
                    ScMatrix* pUInv = GetNewMat(nDim, nDim, nMatInd5);
                    if (!pUInv)
                        PushInt(0);
                    else
                    {
                        bOk = MFastBackSubst(pU, pUInv, nDim, TRUE);
                        if (!bOk)
                            SetNoValue();
                        else
                        {
                            ScMatrix* pPInv = pU;
                            MFastTrans(pP, pPInv, nDim, nDim);
                            ScMatrix* pPInvUInv = pP;
                            MFastMult(pPInv, pUInv, pPInvUInv, nDim, nDim, nDim);
                            ScMatrix* pLInv = pPInv;
                            MFastBackSubst(pL, pLInv, nDim, FALSE);
                            if (nDim == nC)
                                MFastMult(pPInvUInv, pLInv, pMat, nDim, nDim, nDim);
                            else
                            {
                                MFastMult(pPInvUInv, pLInv, pL, nDim, nDim, nDim);
                                for (USHORT i = 0; i < nC; i++)
                                    for (USHORT j = 0; j < nC; j++)
                                        pMat->PutDouble(pL->GetDouble(i, j), i, j);
                            }
                            PushMatrix(pMat);
                            if (nMatInd != MAX_ANZ_MAT)	// vorher neue Matrix
                                nRetMat = nMatInd;		// sonst nRetMat wie vorher
                            ResetNewMat(nMatInd5);
                            delete pUInv;
                        }
                    }
                }
            }
            else
            {
                SetError(errCodeOverflow);
                PushInt(0);
            }
            ResetNewMat(nMatInd4);
            ResetNewMat(nMatInd3);
            ResetNewMat(nMatInd2);
            ResetNewMat(nMatInd1);
            if (nC != nDim)
                delete pA;
            delete pP;
            delete pL;
            delete pU;
        }
    }
}

void ScInterpreter::ScMatMult()
{
    if ( MustHaveParamCount( GetByte(), 2 ) )
    {
        USHORT nMatInd1, nMatInd2;
        ScMatrix* pMat2 = GetMatrix(nMatInd2);
        ScMatrix* pMat1 = GetMatrix(nMatInd1);
        ScMatrix* pRMat;
        if (pMat1 && pMat2)
        {
            if ( pMat1->IsNumeric() && pMat2->IsNumeric() )
            {
                USHORT nC1, nR1, nC2, nR2;
                pMat1->GetDimensions(nC1, nR1);
                pMat2->GetDimensions(nC2, nR2);
                if (nC1 != nR2)
                    SetIllegalParameter();
                else
                {
                    USHORT nMatInd;
                    pRMat = GetNewMat(nC2, nR1, nMatInd);		// Matrixabsicherung
                    if (pRMat)
                    {
                        double sum;
                        for (USHORT i = 0; i < nR1; i++)
                        {
                            for (USHORT j = 0; j < nC2; j++)
                            {
                                sum = 0.0;
                                for (USHORT k = 0; k < nC1; k++)
                                {
                                    sum += pMat1->GetDouble(k,i)*pMat2->GetDouble(j,k);
                                }
                                pRMat->PutDouble(sum, j, i);
                            }
                        }
                        PushMatrix(pRMat);
                        nRetMat = nMatInd;
                    }
                    else
                        SetNoValue();
                }
            }
            else
                SetNoValue();
        }
        else
            SetIllegalParameter();
    }
}

void ScInterpreter::ScMatTrans()
{
    if ( MustHaveParamCount( GetByte(), 1 ) )
    {
        USHORT nMatInd, nMatInd1;
        ScMatrix* pMat = GetMatrix(nMatInd);
        ScMatrix* pRMat;
        if (pMat)
        {
            USHORT nC, nR;
            pMat->GetDimensions(nC, nR);
            pRMat = GetNewMat(nR, nC, nMatInd1);
            pMat->MatTrans(*pRMat);
            PushMatrix(pRMat);
            nRetMat = nMatInd1;
        }
        else
            SetIllegalParameter();
    }
}

/*N*/ ScMatrix* ScInterpreter::MatAdd(ScMatrix* pMat1, ScMatrix* pMat2)
/*N*/ {
/*N*/ 	USHORT nC1, nR1, nC2, nR2, nMinC, nMinR, i, j;
/*N*/ 	pMat1->GetDimensions(nC1, nR1);
/*N*/ 	pMat2->GetDimensions(nC2, nR2);
/*N*/ 	if (nC1 < nC2)
/*N*/ 		nMinC = nC1;
/*N*/ 	else
/*N*/ 		nMinC = nC2;
/*N*/ 	if (nR1 < nR2)
/*N*/ 		nMinR = nR1;
/*N*/ 	else
/*N*/ 		nMinR = nR2;
/*N*/ 	USHORT nMatInd;
/*N*/ 	ScMatrix* pResMat = GetNewMat(nMinC, nMinR, nMatInd);
/*N*/ 	if (pResMat)
/*N*/ 	{
/*N*/ 		for (i = 0; i < nMinC; i++)
/*N*/ 		{
/*N*/ 			for (j = 0; j < nMinR; j++)
/*N*/ 			{
/*N*/ 				if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
/*N*/ 					pResMat->PutDouble( ::rtl::math::approxAdd( pMat1->GetDouble(i,j),
/*N*/ 									   pMat2->GetDouble(i,j)), i, j);
/*N*/ 				else
/*?*/ 					pResMat->PutString(ScGlobal::GetRscString(
/*N*/ 													STR_NO_VALUE), i, j);
/*N*/ 			}
/*N*/ 		}
/*N*/ 		nRetMat = nMatInd;
/*N*/ 	}
/*N*/ 	return pResMat;
/*N*/ }

ScMatrix* ScInterpreter::MatSub(ScMatrix* pMat1, ScMatrix* pMat2)
{
    USHORT nC1, nR1, nC2, nR2, nMinC, nMinR, i, j;
    pMat1->GetDimensions(nC1, nR1);
    pMat2->GetDimensions(nC2, nR2);
    if (nC1 < nC2)
        nMinC = nC1;
    else
        nMinC = nC2;
    if (nR1 < nR2)
        nMinR = nR1;
    else
        nMinR = nR2;
    USHORT nMatInd;
    ScMatrix* pResMat = GetNewMat(nMinC, nMinR, nMatInd);
    if (pResMat)
    {
        for (i = 0; i < nMinC; i++)
        {
            for (j = 0; j < nMinR; j++)
            {
                if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
                    pResMat->PutDouble( ::rtl::math::approxSub( pMat1->GetDouble(i,j),
                                       pMat2->GetDouble(i,j)), i, j);
                else
                    pResMat->PutString(ScGlobal::GetRscString(
                                                    STR_NO_VALUE), i, j);
            }
        }
        nRetMat = nMatInd;
    }
    return pResMat;
}

/*N*/ ScMatrix* ScInterpreter::MatMul(ScMatrix* pMat1, ScMatrix* pMat2)
/*N*/ {
/*N*/ 	USHORT nC1, nR1, nC2, nR2, nMinC, nMinR, i, j;
/*N*/ 	pMat1->GetDimensions(nC1, nR1);
/*N*/ 	pMat2->GetDimensions(nC2, nR2);
/*N*/ 	if (nC1 < nC2)
/*N*/ 		nMinC = nC1;
/*N*/ 	else
/*N*/ 		nMinC = nC2;
/*N*/ 	if (nR1 < nR2)
/*N*/ 		nMinR = nR1;
/*N*/ 	else
/*N*/ 		nMinR = nR2;
/*N*/ 	USHORT nMatInd;
/*N*/ 	ScMatrix* pResMat = GetNewMat(nMinC, nMinR, nMatInd);
/*N*/ 	if (pResMat)
/*N*/ 	{
/*N*/ 		for (i = 0; i < nMinC; i++)
/*N*/ 		{
/*N*/ 			for (j = 0; j < nMinR; j++)
/*N*/ 			{
/*N*/ 				if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
/*N*/ 					pResMat->PutDouble(pMat1->GetDouble(i,j) *
/*N*/ 									   pMat2->GetDouble(i,j), i, j);
/*N*/ 				else
/*?*/ 					pResMat->PutString(ScGlobal::GetRscString(
/*N*/ 													STR_NO_VALUE), i, j);
/*N*/ 			}
/*N*/ 		}
/*N*/ 		nRetMat = nMatInd;
/*N*/ 	}
/*N*/ 	return pResMat;
/*N*/ }

ScMatrix* ScInterpreter::MatDiv(ScMatrix* pMat1, ScMatrix* pMat2)
{
    USHORT nC1, nR1, nC2, nR2, nMinC, nMinR, i, j;
    pMat1->GetDimensions(nC1, nR1);
    pMat2->GetDimensions(nC2, nR2);
    if (nC1 < nC2)
        nMinC = nC1;
    else
        nMinC = nC2;
    if (nR1 < nR2)
        nMinR = nR1;
    else
        nMinR = nR2;
    USHORT nMatInd;
    ScMatrix* pResMat = GetNewMat(nMinC, nMinR, nMatInd);
    if (pResMat)
    {
        for (i = 0; i < nMinC; i++)
        {
            for (j = 0; j < nMinR; j++)
            {
                if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
                    pResMat->PutDouble(pMat1->GetDouble(i,j) /
                                       pMat2->GetDouble(i,j), i, j);
                else
                    pResMat->PutString(ScGlobal::GetRscString(
                                                    STR_NO_VALUE), i, j);
            }
        }
        nRetMat = nMatInd;
    }
    return pResMat;
}

ScMatrix* ScInterpreter::MatPow(ScMatrix* pMat1, ScMatrix* pMat2)
{
    USHORT nC1, nR1, nC2, nR2, nMinC, nMinR, i, j;
    pMat1->GetDimensions(nC1, nR1);
    pMat2->GetDimensions(nC2, nR2);
    if (nC1 < nC2)
        nMinC = nC1;
    else
        nMinC = nC2;
    if (nR1 < nR2)
        nMinR = nR1;
    else
        nMinR = nR2;
    USHORT nMatInd;
    ScMatrix* pResMat = GetNewMat(nMinC, nMinR, nMatInd);
    if (pResMat)
    {
        for (i = 0; i < nMinC; i++)
        {
            for (j = 0; j < nMinR; j++)
            {
                if (pMat1->IsValueOrEmpty(i,j) && pMat2->IsValueOrEmpty(i,j))
                    pResMat->PutDouble(pow(pMat1->GetDouble(i,j),
                                           pMat2->GetDouble(i,j)), i, j);
                else
                    pResMat->PutString(ScGlobal::GetRscString(
                                                    STR_NO_VALUE), i, j);
            }
        }
        nRetMat = nMatInd;
    }
    return pResMat;
}

ScMatrix* ScInterpreter::MatConcat(ScMatrix* pMat1, ScMatrix* pMat2)
{
    USHORT nC1, nR1, nC2, nR2, nMinC, nMinR, i, j;
    pMat1->GetDimensions(nC1, nR1);
    pMat2->GetDimensions(nC2, nR2);
    if (nC1 < nC2)
        nMinC = nC1;
    else
        nMinC = nC2;
    if (nR1 < nR2)
        nMinR = nR1;
    else
        nMinR = nR2;
    USHORT nMatInd;
    ScMatrix* pResMat = GetNewMat(nMinC, nMinR, nMatInd);
    if (pResMat)
    {
        for (i = 0; i < nMinC; i++)
        {
            for (j = 0; j < nMinR; j++)
            {
                if (pMat1->IsString(i,j) && pMat2->IsString(i,j))
                {
                    String aTmp( pMat1->GetString(i,j) );
                    aTmp += pMat2->GetString(i,j);
                    pResMat->PutString( aTmp , i, j);
                }
                else
                    pResMat->PutString(ScGlobal::GetRscString(
                                                    STR_NO_VALUE), i, j);
//! TODO: Xcl does concatenate value strings
            }
        }
        nRetMat = nMatInd;
    }
    return pResMat;
}


// fuer DATE, TIME, DATETIME
/*N*/ void lcl_GetDiffDateTimeFmtType( short& nFuncFmt, short nFmt1, short nFmt2 )
/*N*/ {
/*N*/ 	if ( nFmt1 != NUMBERFORMAT_UNDEFINED || nFmt2 != NUMBERFORMAT_UNDEFINED )
/*N*/ 	{
/*N*/ 		if ( nFmt1 == nFmt2 )
/*N*/ 		{
/*N*/ 			if ( nFmt1 == NUMBERFORMAT_TIME || nFmt1 == NUMBERFORMAT_DATETIME )
/*N*/ 				nFuncFmt = NUMBERFORMAT_TIME;	// Zeiten ergeben Zeit
/*N*/ 			// else: nichts besonderes, Zahl (Datum - Datum := Tage)
/*N*/ 		}
/*N*/ 		else if ( nFmt1 == NUMBERFORMAT_UNDEFINED )
/*N*/ 			nFuncFmt = nFmt2;	// z.B. Datum + Tage := Datum
/*N*/ 		else if ( nFmt2 == NUMBERFORMAT_UNDEFINED )
/*N*/ 			nFuncFmt = nFmt1;
/*N*/ 		else
/*N*/ 		{
/*N*/ 			if ( nFmt1 == NUMBERFORMAT_DATE || nFmt2 == NUMBERFORMAT_DATE ||
/*N*/ 				nFmt1 == NUMBERFORMAT_DATETIME || nFmt2 == NUMBERFORMAT_DATETIME )
/*N*/ 			{
/*N*/ 				if ( nFmt1 == NUMBERFORMAT_TIME || nFmt2 == NUMBERFORMAT_TIME )
/*N*/ 					nFuncFmt = NUMBERFORMAT_DATETIME;	// Datum + Zeit
/*N*/ 			}
/*N*/ 		}
/*N*/ 	}
/*N*/ }


/*N*/ void ScInterpreter::ScAdd()
/*N*/ {
/*N*/ 	ScMatrix* pMat1 = NULL;
/*N*/ 	ScMatrix* pMat2 = NULL;
/*N*/ 	double fVal1 = 0.0, fVal2 = 0.0;
/*N*/ 	USHORT nMatInd1, nMatInd2;
/*N*/ 	short nFmt1, nFmt2;
/*N*/ 	nFmt1 = nFmt2 = NUMBERFORMAT_UNDEFINED;
/*N*/ 	short nFmtCurrencyType = nCurFmtType;
/*N*/ 	ULONG nFmtCurrencyIndex = nCurFmtIndex;
/*N*/     short nFmtPercentType = nCurFmtType;
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*N*/ 		pMat2 = GetMatrix(nMatInd2);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal2 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_DATE :
/*N*/ 			case NUMBERFORMAT_TIME :
/*N*/ 			case NUMBERFORMAT_DATETIME :
/*N*/ 				nFmt2 = nCurFmtType;
/*N*/ 			break;
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/             case NUMBERFORMAT_PERCENT :
/*N*/                 nFmtPercentType = NUMBERFORMAT_PERCENT;
/*N*/             break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*N*/ 		pMat1 = GetMatrix(nMatInd1);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal1 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_DATE :
/*N*/ 			case NUMBERFORMAT_TIME :
/*N*/ 			case NUMBERFORMAT_DATETIME :
/*N*/ 				nFmt1 = nCurFmtType;
/*N*/ 			break;
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/             case NUMBERFORMAT_PERCENT :
/*N*/                 nFmtPercentType = NUMBERFORMAT_PERCENT;
/*N*/             break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	if (pMat1 && pMat2)
/*N*/ 	{
/*N*/ 		ScMatrix* pResMat = MatAdd(pMat1, pMat2);
/*N*/ 		if (!pResMat)
/*?*/ 			SetNoValue();
/*N*/ 		else
/*N*/ 			PushMatrix(pResMat);
/*N*/ 	}
/*N*/ 	else if (pMat1 || pMat2)
/*N*/ 	{
/*?*/ 		double fVal;
/*?*/ 		ScMatrix* pMat = pMat1;
/*?*/ 		if (!pMat)
/*?*/ 		{
/*?*/ 			fVal = fVal1;
/*?*/ 			pMat = pMat2;
/*?*/ 		}
/*?*/ 		else
/*?*/ 			fVal = fVal2;
/*?*/ 		USHORT nC, nR;
/*?*/ 		pMat->GetDimensions(nC, nR);
/*?*/ 		USHORT nMatInd;
/*?*/ 		ScMatrix* pResMat = GetNewMat(nC, nR, nMatInd);
/*?*/ 		if (pResMat)
/*?*/ 		{
/*?*/ 			ULONG nCount = (ULONG) nC * nR;
/*?*/ 			for ( ULONG i = 0; i < nCount; i++ )
/*?*/ 			{
/*?*/ 				if (pMat->IsValue(i))
/*?*/ 					pResMat->PutDouble( ::rtl::math::approxAdd( pMat->GetDouble(i), fVal), i);
/*?*/ 				else
/*?*/ 					pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*?*/ 			}
/*?*/ 			PushMatrix(pResMat);
/*?*/ 			nRetMat = nMatInd;
/*?*/ 		}
/*?*/ 		else
/*?*/ 			SetNoValue();
/*N*/ 	}
/*N*/ 	else
/*N*/ 		PushDouble( ::rtl::math::approxAdd( fVal1, fVal2 ) );
/*N*/ 	if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
/*N*/ 	{
/*N*/ 		nFuncFmtType = nFmtCurrencyType;
/*N*/ 		nFuncFmtIndex = nFmtCurrencyIndex;
/*N*/ 	}
/*N*/ 	else
/*N*/     {
/*N*/ 		lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
/*N*/         if ( nFmtPercentType == NUMBERFORMAT_PERCENT && nFuncFmtType == NUMBERFORMAT_NUMBER )
/*N*/             nFuncFmtType = NUMBERFORMAT_PERCENT;
/*N*/     }
/*N*/ }

/*N*/ void ScInterpreter::ScAmpersand()
/*N*/ {
/*N*/ 	ScMatrix* pMat1 = NULL;
/*N*/ 	ScMatrix* pMat2 = NULL;
/*N*/ 	String sStr1, sStr2;
/*N*/ 	USHORT nMatInd1, nMatInd2;
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*?*/ 		pMat2 = GetMatrix(nMatInd2);
/*N*/ 	else
/*N*/ 		sStr2 = GetString();
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*?*/ 		pMat1 = GetMatrix(nMatInd1);
/*N*/ 	else
/*N*/ 		sStr1 = GetString();
/*N*/ 	if (pMat1 && pMat2)
/*N*/ 	{
/*?*/ 		ScMatrix* pResMat = MatConcat(pMat1, pMat2);
/*?*/ 		if (!pResMat)
/*?*/ 			SetNoValue();
/*?*/ 		else
/*?*/ 			PushMatrix(pResMat);
/*N*/ 	}
/*N*/ 	else if (pMat1 || pMat2)
/*N*/ 	{
/*?*/ 		String sStr;
/*?*/ 		BOOL bFlag;
/*?*/ 		ScMatrix* pMat = pMat1;
/*?*/ 		if (!pMat)
/*?*/ 		{
/*?*/ 			sStr = sStr1;
/*?*/ 			pMat = pMat2;
/*?*/ 			bFlag = TRUE;			// double - Matrix
/*?*/ 		}
/*?*/ 		else
/*?*/ 		{
/*?*/ 			sStr = sStr2;
/*?*/ 			bFlag = FALSE;			// Matrix - double
/*?*/ 		}
/*?*/ 		USHORT nC, nR;
/*?*/ 		pMat->GetDimensions(nC, nR);
/*?*/ 		USHORT nMatInd;
/*?*/ 		ScMatrix* pResMat = GetNewMat(nC, nR, nMatInd);
/*?*/ 		if (pResMat)
/*?*/ 		{
/*?*/ 			ULONG nCount = (ULONG) nC * nR;
/*?*/ 			if (bFlag)
/*?*/ 			{
/*?*/ 				for ( ULONG i = 0; i < nCount; i++ )
/*?*/ 					if (!pMat->IsValue(i))
/*?*/ 					{
/*?*/ 						String sS = sStr;
/*?*/ 						sS += pMat->GetString(i);
/*?*/ 						pResMat->PutString(sS, i);
/*?*/ 					}
/*?*/ 					else
/*?*/ 						pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*?*/ 			}
/*?*/ 			else
/*?*/ 			{
/*?*/ 				for ( ULONG i = 0; i < nCount; i++ )
/*?*/ 					if (!pMat->IsValue(i))
/*?*/ 					{
/*?*/ 						String sS = pMat->GetString(i);
/*?*/ 						sS += sStr;
/*?*/ 						pResMat->PutString(sS, i);
/*?*/ 					}
/*?*/ 					else
/*?*/ 						pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*?*/ 			}
/*?*/ 			PushMatrix(pResMat);
/*?*/ 			nRetMat = nMatInd;
/*?*/ 		}
/*?*/ 		else
/*?*/ 			SetNoValue();
/*N*/ 	}
/*N*/ 	else
/*N*/ 	{
/*N*/ 		if ( CheckStringResultLen( sStr1, sStr2 ) )
/*N*/ 			sStr1 += sStr2;
/*N*/ 		PushString(sStr1);
/*N*/ 	}
/*N*/ }

/*N*/ void ScInterpreter::ScSub()
/*N*/ {
/*N*/ 	ScMatrix* pMat1 = NULL;
/*N*/ 	ScMatrix* pMat2 = NULL;
/*N*/ 	double fVal1 = 0.0, fVal2 = 0.0;
/*N*/ 	USHORT nMatInd1, nMatInd2;
/*N*/ 	short nFmt1, nFmt2;
/*N*/ 	nFmt1 = nFmt2 = NUMBERFORMAT_UNDEFINED;
/*N*/ 	short nFmtCurrencyType = nCurFmtType;
/*N*/ 	ULONG nFmtCurrencyIndex = nCurFmtIndex;
/*N*/     short nFmtPercentType = nCurFmtType;
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*N*/ 		pMat2 = GetMatrix(nMatInd2);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal2 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_DATE :
/*N*/ 			case NUMBERFORMAT_TIME :
/*N*/ 			case NUMBERFORMAT_DATETIME :
/*N*/ 				nFmt2 = nCurFmtType;
/*N*/ 			break;
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/             case NUMBERFORMAT_PERCENT :
/*N*/                 nFmtPercentType = NUMBERFORMAT_PERCENT;
/*N*/             break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*?*/ 		pMat1 = GetMatrix(nMatInd1);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal1 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_DATE :
/*N*/ 			case NUMBERFORMAT_TIME :
/*N*/ 			case NUMBERFORMAT_DATETIME :
/*N*/ 				nFmt1 = nCurFmtType;
/*N*/ 			break;
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/             case NUMBERFORMAT_PERCENT :
/*N*/                 nFmtPercentType = NUMBERFORMAT_PERCENT;
/*N*/             break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	if (pMat1 && pMat2)
/*N*/ 	{
/*?*/ 		ScMatrix* pResMat = MatSub(pMat1, pMat2);
/*?*/ 		if (!pResMat)
/*?*/ 			SetNoValue();
/*?*/ 		else
/*?*/ 			PushMatrix(pResMat);
/*N*/ 	}
/*N*/ 	else if (pMat1 || pMat2)
/*N*/ 	{
/*N*/ 		double fVal;
/*N*/ 		BOOL bFlag;
/*N*/ 		ScMatrix* pMat = pMat1;
/*N*/ 		if (!pMat)
/*N*/ 		{
/*N*/ 			fVal = fVal1;
/*N*/ 			pMat = pMat2;
/*N*/ 			bFlag = TRUE;			// double - Matrix
/*N*/ 		}
/*N*/ 		else
/*N*/ 		{
/*N*/ 			fVal = fVal2;
/*N*/ 			bFlag = FALSE;			// Matrix - double
/*N*/ 		}
/*N*/ 		USHORT nC, nR;
/*N*/ 		pMat->GetDimensions(nC, nR);
/*N*/ 		USHORT nMatInd;
/*N*/ 		ScMatrix* pResMat = GetNewMat(nC, nR, nMatInd);
/*N*/ 		if (pResMat)
/*N*/ 		{	// mehr klammern wg. compiler macke
/*N*/ 			ULONG nCount = (ULONG) nC * nR;
/*N*/ 			if (bFlag)
/*N*/ 			{	for ( ULONG i = 0; i < nCount; i++ )
/*N*/ 				{	if (pMat->IsValue(i))
/*N*/ 						pResMat->PutDouble( ::rtl::math::approxSub( fVal, pMat->GetDouble(i)), i);
/*N*/ 					else
/*?*/ 						pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*N*/ 				}
/*N*/ 			}
/*N*/ 			else
/*?*/ 			{	for ( ULONG i = 0; i < nCount; i++ )
/*?*/ 				{	if (pMat->IsValue(i))
/*?*/ 						pResMat->PutDouble( ::rtl::math::approxSub( pMat->GetDouble(i), fVal), i);
/*?*/ 					else
/*?*/ 						pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*?*/ 				}
/*N*/ 			}
/*N*/ 			PushMatrix(pResMat);
/*N*/ 			nRetMat = nMatInd;
/*N*/ 		}
/*N*/ 		else
/*?*/ 			SetNoValue();
/*N*/ 	}
/*N*/ 	else
/*N*/ 		PushDouble( ::rtl::math::approxSub( fVal1, fVal2 ) );
/*N*/ 	if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
/*N*/ 	{
/*N*/ 		nFuncFmtType = nFmtCurrencyType;
/*N*/ 		nFuncFmtIndex = nFmtCurrencyIndex;
/*N*/ 	}
/*N*/ 	else
/*N*/     {
/*N*/ 		lcl_GetDiffDateTimeFmtType( nFuncFmtType, nFmt1, nFmt2 );
/*N*/         if ( nFmtPercentType == NUMBERFORMAT_PERCENT && nFuncFmtType == NUMBERFORMAT_NUMBER )
/*N*/             nFuncFmtType = NUMBERFORMAT_PERCENT;
/*N*/     }
/*N*/ }

/*N*/ void ScInterpreter::ScMul()
/*N*/ {
/*N*/ 	ScMatrix* pMat1 = NULL;
/*N*/ 	ScMatrix* pMat2 = NULL;
/*N*/ 	double fVal1 = 0.0, fVal2 = 0.0;
/*N*/ 	USHORT nMatInd1, nMatInd2;
/*N*/ 	short nFmtCurrencyType = nCurFmtType;
/*N*/ 	ULONG nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*N*/ 		pMat2 = GetMatrix(nMatInd2);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal2 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*N*/ 		pMat1 = GetMatrix(nMatInd1);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal1 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	if (pMat1 && pMat2)
/*N*/ 	{
/*N*/ 		ScMatrix* pResMat = MatMul(pMat1, pMat2);
/*N*/ 		if (!pResMat)
/*?*/ 			SetNoValue();
/*N*/ 		else
/*N*/ 			PushMatrix(pResMat);
/*N*/ 	}
/*N*/ 	else if (pMat1 || pMat2)
/*N*/ 	{
/*N*/ 		double fVal;
/*N*/ 		ScMatrix* pMat = pMat1;
/*N*/ 		if (!pMat)
/*N*/ 		{
/*N*/ 			fVal = fVal1;
/*N*/ 			pMat = pMat2;
/*N*/ 		}
/*N*/ 		else
/*N*/ 			fVal = fVal2;
/*N*/ 		USHORT nC, nR;
/*N*/ 		pMat->GetDimensions(nC, nR);
/*N*/ 		USHORT nMatInd;
/*N*/ 		ScMatrix* pResMat = GetNewMat(nC, nR, nMatInd);
/*N*/ 		if (pResMat)
/*N*/ 		{
/*N*/ 			ULONG nCount = (ULONG) nC * nR;
/*N*/ 			for ( ULONG i = 0; i < nCount; i++ )
/*N*/ 				if (pMat->IsValue(i))
/*N*/ 					pResMat->PutDouble(pMat->GetDouble(i)*fVal, i);
/*N*/ 				else
/*N*/ 					pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*N*/ 			PushMatrix(pResMat);
/*N*/ 			nRetMat = nMatInd;
/*N*/ 		}
/*N*/ 		else
/*?*/ 			SetNoValue();
/*N*/ 	}
/*N*/ 	else
/*N*/ 		PushDouble(fVal1 * fVal2);
/*N*/ 	if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY )
/*N*/ 	{
/*N*/ 		nFuncFmtType = nFmtCurrencyType;
/*N*/ 		nFuncFmtIndex = nFmtCurrencyIndex;
/*N*/ 	}
/*N*/ }

/*N*/ void ScInterpreter::ScDiv()
/*N*/ {
/*N*/ 	ScMatrix* pMat1 = NULL;
/*N*/ 	ScMatrix* pMat2 = NULL;
/*N*/ 	double fVal1 = 0.0, fVal2 = 0.0;
/*N*/ 	USHORT nMatInd1, nMatInd2;
/*N*/ 	short nFmtCurrencyType = nCurFmtType;
/*N*/ 	ULONG nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 	short nFmtCurrencyType2 = NUMBERFORMAT_UNDEFINED;
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*?*/ 		pMat2 = GetMatrix(nMatInd2);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal2 = GetDouble();
/*N*/ 		// hier kein Currency uebernehmen, 123kg/456DM sind nicht DM
/*N*/ 		nFmtCurrencyType2 = nCurFmtType;
/*N*/ 	}
/*N*/ 	MatrixDoubleRefToMatrix();
/*N*/ 	if ( GetStackType() == svMatrix )
/*?*/ 		pMat1 = GetMatrix(nMatInd1);
/*N*/ 	else
/*N*/ 	{
/*N*/ 		fVal1 = GetDouble();
/*N*/ 		switch ( nCurFmtType )
/*N*/ 		{
/*N*/ 			case NUMBERFORMAT_CURRENCY :
/*N*/ 				nFmtCurrencyType = nCurFmtType;
/*N*/ 				nFmtCurrencyIndex = nCurFmtIndex;
/*N*/ 			break;
/*N*/ 		}
/*N*/ 	}
/*N*/ 	if (pMat1 && pMat2)
/*N*/ 	{
/*?*/ 		ScMatrix* pResMat = MatDiv(pMat1, pMat2);
/*?*/ 		if (!pResMat)
/*?*/ 			SetNoValue();
/*?*/ 		else
/*?*/ 			PushMatrix(pResMat);
/*N*/ 	}
/*N*/ 	else if (pMat1 || pMat2)
/*N*/ 	{
/*?*/ 		double fVal;
/*?*/ 		BOOL bFlag;
/*?*/ 		ScMatrix* pMat = pMat1;
/*?*/ 		if (!pMat)
/*?*/ 		{
/*?*/ 			fVal = fVal1;
/*?*/ 			pMat = pMat2;
/*?*/ 			bFlag = TRUE;			// double - Matrix
/*?*/ 		}
/*?*/ 		else
/*?*/ 		{
/*?*/ 			fVal = fVal2;
/*?*/ 			bFlag = FALSE;			// Matrix - double
/*?*/ 		}
/*?*/ 		USHORT nC, nR;
/*?*/ 		pMat->GetDimensions(nC, nR);
/*?*/ 		USHORT nMatInd;
/*?*/ 		ScMatrix* pResMat = GetNewMat(nC, nR, nMatInd);
/*?*/ 		if (pResMat)
/*?*/ 		{
/*?*/ 			ULONG nCount = (ULONG) nC * nR;
/*?*/ 			if (bFlag)
/*?*/ 			{	for ( ULONG i = 0; i < nCount; i++ )
/*?*/ 					if (pMat->IsValue(i))
/*?*/ 						pResMat->PutDouble(fVal / pMat->GetDouble(i), i);
/*?*/ 					else
/*?*/ 						pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*?*/ 			}
/*?*/ 			else
/*?*/ 			{	for ( ULONG i = 0; i < nCount; i++ )
/*?*/ 					if (pMat->IsValue(i))
/*?*/ 						pResMat->PutDouble(pMat->GetDouble(i) / fVal, i);
/*?*/ 					else
/*?*/ 						pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
/*?*/ 			}
/*?*/ 			PushMatrix(pResMat);
/*?*/ 			nRetMat = nMatInd;
/*?*/ 		}
/*?*/ 		else
/*?*/ 			SetNoValue();
/*N*/ 	}
/*N*/ 	else
/*N*/ 		PushDouble(fVal1 / fVal2);
/*N*/ 	if ( nFmtCurrencyType == NUMBERFORMAT_CURRENCY && nFmtCurrencyType2 != NUMBERFORMAT_CURRENCY )
/*N*/ 	{	// auch DM/DM ist nicht DM bzw. DEM/EUR nicht DEM
/*N*/ 		nFuncFmtType = nFmtCurrencyType;
/*N*/ 		nFuncFmtIndex = nFmtCurrencyIndex;
/*N*/ 	}
/*N*/ }

void ScInterpreter::ScPower()
{
    if ( MustHaveParamCount( GetByte(), 2 ) )
        ScPow();
}

void ScInterpreter::ScPow()
{
    ScMatrix* pMat1 = NULL;
    ScMatrix* pMat2 = NULL;
    double fVal1 = 0.0, fVal2 = 0.0;
    USHORT nMatInd1, nMatInd2;
    MatrixDoubleRefToMatrix();
    if ( GetStackType() == svMatrix )
        pMat2 = GetMatrix(nMatInd2);
    else
        fVal2 = GetDouble();
    MatrixDoubleRefToMatrix();
    if ( GetStackType() == svMatrix )
        pMat1 = GetMatrix(nMatInd1);
    else
        fVal1 = GetDouble();
    if (pMat1 && pMat2)
    {
        ScMatrix* pResMat = MatPow(pMat1, pMat2);
        if (!pResMat)
            SetNoValue();
        else
            PushMatrix(pResMat);
    }
    else if (pMat1 || pMat2)
    {
        double fVal;
        BOOL bFlag;
        ScMatrix* pMat = pMat1;
        if (!pMat)
        {
            fVal = fVal1;
            pMat = pMat2;
            bFlag = TRUE;			// double - Matrix
        }
        else
        {
            fVal = fVal2;
            bFlag = FALSE;			// Matrix - double
        }
        USHORT nC, nR;
        pMat->GetDimensions(nC, nR);
        USHORT nMatInd;
        ScMatrix* pResMat = GetNewMat(nC, nR, nMatInd);
        if (pResMat)
        {
            ULONG nCount = (ULONG) nC * nR;
            if (bFlag)
            {	for ( ULONG i = 0; i < nCount; i++ )
                    if (pMat->IsValue(i))
                        pResMat->PutDouble(pow(fVal,pMat->GetDouble(i)), i);
                    else
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
            }
            else
            {	for ( ULONG i = 0; i < nCount; i++ )
                    if (pMat->IsValue(i))
                        pResMat->PutDouble(pow(pMat->GetDouble(i),fVal), i);
                    else
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i);
            }
            PushMatrix(pResMat);
            nRetMat = nMatInd;
        }
        else
            SetNoValue();
    }
    else
        PushDouble(pow(fVal1,fVal2));
}

void ScInterpreter::ScSumProduct()
{
    BYTE nParamCount = GetByte();
    if ( !MustHaveParamCount( nParamCount, 1, 30 ) )
        return;

    ScMatrix* pMat1 = NULL;
    ScMatrix* pMat2 = NULL;
    ScMatrix* pMat  = NULL;
    USHORT nMatInd1, nMatInd2;
    pMat2 = GetMatrix(nMatInd2);
    if (!pMat2)
    {
        SetIllegalParameter();
        return;
    }
    USHORT nC, nR, nC1, nR1;
    pMat2->GetDimensions(nC, nR);
    pMat = pMat2;
    for (USHORT i = 1; i < nParamCount; i++)
    {
        pMat1 = GetMatrix(nMatInd1);
        if (!pMat1)
        {
            SetIllegalParameter();
            return;
        }
        pMat1->GetDimensions(nC1, nR1);
        if (nC1 != nC || nR1 != nR)
        {
            SetNoValue();
            return;
        }
        ScMatrix* pResMat = MatMul(pMat1, pMat);
        if (!pResMat)
        {
            SetNoValue();
            return;
        }
        else
            pMat = pResMat;
    }
    double fSum = 0.0;
    ULONG nCount = pMat->GetElementCount();
    for (ULONG j = 0; j < nCount; j++)
        if (!pMat->IsString(j))
            fSum += pMat->GetDouble(j);
    PushDouble(fSum);
}

void ScInterpreter::ScSumX2MY2()
{
    if ( !MustHaveParamCount( GetByte(), 2 ) )
        return;

    ScMatrix* pMat1 = NULL;
    ScMatrix* pMat2 = NULL;
    USHORT nMatInd1, nMatInd2, i, j;
    pMat2 = GetMatrix(nMatInd2);
    pMat1 = GetMatrix(nMatInd1);
    if (!pMat2 || !pMat1)
    {
        SetIllegalParameter();
        return;
    }
    USHORT nC2, nR2, nC1, nR1;
    pMat2->GetDimensions(nC2, nR2);
    pMat1->GetDimensions(nC1, nR1);
    if (nC1 != nC2 || nR1 != nR2)
    {
        SetNoValue();
        return;
    }
    double fVal, fSum = 0.0;
    for (i = 0; i < nC1; i++)
        for (j = 0; j < nR1; j++)
            if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
            {
                fVal = pMat1->GetDouble(i,j);
                fSum += fVal * fVal;
                fVal = pMat2->GetDouble(i,j);
                fSum -= fVal * fVal;
            }
    PushDouble(fSum);
}

void ScInterpreter::ScSumX2DY2()
{
    if ( !MustHaveParamCount( GetByte(), 2 ) )
        return;

    ScMatrix* pMat1 = NULL;
    ScMatrix* pMat2 = NULL;
    USHORT nMatInd1, nMatInd2, i, j;
    pMat2 = GetMatrix(nMatInd2);
    pMat1 = GetMatrix(nMatInd1);
    if (!pMat2 || !pMat1)
    {
        SetIllegalParameter();
        return;
    }
    USHORT nC2, nR2, nC1, nR1;
    pMat2->GetDimensions(nC2, nR2);
    pMat1->GetDimensions(nC1, nR1);
    if (nC1 != nC2 || nR1 != nR2)
    {
        SetNoValue();
        return;
    }
    double fVal, fSum = 0.0;
    for (i = 0; i < nC1; i++)
        for (j = 0; j < nR1; j++)
            if (!pMat1->IsString(i,j) && !pMat2->IsString(i,j))
            {
                fVal = pMat1->GetDouble(i,j);
                fSum += fVal * fVal;
                fVal = pMat2->GetDouble(i,j);
                fSum += fVal * fVal;
            }
    PushDouble(fSum);
}

void ScInterpreter::ScSumXMY2()
{
    if ( !MustHaveParamCount( GetByte(), 2 ) )
        return;

    ScMatrix* pMat1 = NULL;
    ScMatrix* pMat2 = NULL;
    USHORT nMatInd1, nMatInd2;
    pMat2 = GetMatrix(nMatInd2);
    pMat1 = GetMatrix(nMatInd1);
    if (!pMat2 || !pMat1)
    {
        SetIllegalParameter();
        return;
    }
    USHORT nC2, nR2, nC1, nR1;
    pMat2->GetDimensions(nC2, nR2);
    pMat1->GetDimensions(nC1, nR1);
    if (nC1 != nC2 || nR1 != nR2)
    {
        SetNoValue();
        return;
    }
    ScMatrix* pResMat = MatSub(pMat1, pMat2);
    if (!pResMat)
    {
        SetNoValue();
        return;
    }
    else
    {
        double fVal, fSum = 0.0;
        ULONG nCount = pResMat->GetElementCount();
        for (ULONG i = 0; i < nCount; i++)
            if (!pResMat->IsString(i))
            {
                fVal = pResMat->GetDouble(i);
                fSum += fVal * fVal;
            }
        PushDouble(fSum);
    }
}

void ScInterpreter::ScFrequency()
{
    if ( !MustHaveParamCount( GetByte(), 2 ) )
        return;

    USHORT nMatInd;
    double* pSortArray1 = NULL;
    ULONG nSize1 = 0;
    GetSortArray(1, &pSortArray1, nSize1);
    if (nGlobalError)
        SetNoValue();
    double* pSortArray2 = NULL;
    ULONG nSize2 = 0;
    GetSortArray(1, &pSortArray2, nSize2);
    if (!pSortArray2 || nSize2 == 0 || nGlobalError)
    {
        if (pSortArray1)
            delete pSortArray1;
        if (pSortArray2)
            delete pSortArray2;
        SetNoValue();
        return;
    }
    ScMatrix* pResMat = GetNewMat(1,(USHORT)nSize1+1,nMatInd);
    if (!pResMat)
    {
        if (pSortArray1)
            delete pSortArray1;
        if (pSortArray2)
            delete pSortArray2;
        SetNoValue();
        return;
    }

    USHORT j;
    ULONG i = 0;
    ULONG nCount;
    for (j = 0; j < nSize1; j++)
    {
        nCount = 0;
        while (i < nSize2 && pSortArray2[i] <= pSortArray1[j])
        {
            nCount++;
            i++;
        }
        pResMat->PutDouble((double) nCount, j);
    }
    pResMat->PutDouble((double) (nSize2-i), j);
    if (pSortArray1)
        delete pSortArray1;
    if (pSortArray2)
        delete pSortArray2;
    PushMatrix(pResMat);
    nRetMat = nMatInd;
}

BOOL ScInterpreter::RGetVariances( ScMatrix* pV, ScMatrix* pX,
        USHORT nC, USHORT nR, BOOL bSwapColRow, BOOL bZeroConstant )
{	// multiple Regression: Varianzen der Koeffizienten
    // bSwapColRow==TRUE : Koeffizienten in Zeilen statt Spalten angeordnet
    USHORT i, j, k, nMatInd;
    double sum;
    ScMatrix* pC = GetNewMat(nC, nC, nMatInd);
    if ( !pC )
        return FALSE;
    // X transformiert mit X multipziert, X'X Matrix
    if ( !bZeroConstant )
    {	// in der X-Designmatrix existiert ein gedachtes X0j==1
        if ( bSwapColRow )
        {
            for ( i=0; i<nC; i++ )
            {
                for ( j=0; j<nC; j++ )
                {
                    sum = 0.0;
                    for ( k=0; k<nR; k++ )
                    {
                        sum += (j==0 ? 1 : pX->GetDouble(k,j-1))
                            * (i==0 ? 1 : pX->GetDouble(k,i-1));
                    }
                    pC->PutDouble(sum, i, j);
                }
            }
        }
        else
        {
            for ( i=0; i<nC; i++ )
            {
                for ( j=0; j<nC; j++ )
                {
                    sum = 0.0;
                    for ( k=0; k<nR; k++ )
                    {
                        sum += (j==0 ? 1 : pX->GetDouble(j-1,k))
                            * (i==0 ? 1 : pX->GetDouble(i-1,k));
                    }
                    pC->PutDouble(sum, i, j);
                }
            }
        }
    }
    else
    {
        if ( bSwapColRow )
        {
            for ( i=0; i<nC; i++ )
            {
                for ( j=0; j<nC; j++ )
                {
                    sum = 0.0;
                    for ( k=0; k<nR; k++ )
                    {
                        sum += pX->GetDouble(k,j) * pX->GetDouble(k,i);
                    }
                    pC->PutDouble(sum, i, j);
                }
            }
        }
        else
        {
            for ( i=0; i<nC; i++ )
            {
                for ( j=0; j<nC; j++ )
                {
                    sum = 0.0;
                    for ( k=0; k<nR; k++ )
                    {
                        sum += pX->GetDouble(j,k) * pX->GetDouble(i,k);
                    }
                    pC->PutDouble(sum, i, j);
                }
            }
        }
    }
    // X'X Inverse
    BOOL bOk = TRUE;
    USHORT nErr = nGlobalError;
    PushMatrix(pC);
    BYTE nTmp = cPar;
    cPar = 1;
    ScMatInv();
    cPar = nTmp;
    if ( nGlobalError )
    {
        nGlobalError = nErr;
        bOk = FALSE;
    }
    else
    {
        Pop();		// pC bleibt erhalten
        // Varianzen auf der Diagonalen, andere sind Kovarianzen
        for (i = 0; i < nC; i++)
            pV->PutDouble(pC->GetDouble(i, i), i);
    }
    delete pC;
    ResetNewMat(nMatInd);
    return bOk;
}

void ScInterpreter::ScRGP()
{
    BYTE nParamCount = GetByte();
    if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
        return;
    BOOL bConstant, bStats;
    if (nParamCount == 4)
        bStats = GetBool();
    else
        bStats = FALSE;
    if (nParamCount >= 3)
        bConstant = GetBool();
    else
        bConstant = TRUE;
    USHORT nMatInd1, nMatInd2;
    ScMatrix* pMatX;
    ScMatrix* pMatY;
    if (nParamCount >= 2)
        pMatX = GetMatrix(nMatInd2);
    else
        pMatX = NULL;
    pMatY = GetMatrix(nMatInd1);
    if (!pMatY)
    {
        SetIllegalParameter();
        return;
    }
    BYTE nCase;							// 1 = normal, 2,3 = mehrfach
    USHORT nCX, nRX, nCY, nRY, M, N;
    pMatY->GetDimensions(nCY, nRY);
    ULONG nCountY = (ULONG) nCY * nRY;
    for ( ULONG i = 0; i < nCountY; i++ )
        if (!pMatY->IsValue(i))
        {
            SetIllegalArgument();
            return;
        }
    if (pMatX)
    {
        pMatX->GetDimensions(nCX, nRX);
        ULONG nCountX = (ULONG) nCX * nRX;
        for ( ULONG i = 0; i < nCountX; i++ )
            if (!pMatX->IsValue(i))
            {
                SetIllegalArgument();
                return;
            }
        if (nCX == nCY && nRX == nRY)
            nCase = 1;					// einfache Regression
        else if (nCY != 1 && nRY != 1)
        {
            SetIllegalParameter();
            return;
        }
        else if (nCY == 1)
        {
            if (nRX != nRY)
            {
                SetIllegalParameter();
                return;
            }
            else
            {
                nCase = 2;				// zeilenweise
                N = nRY;
                M = nCX;
            }
        }
        else if (nCX != nCY)
        {
            SetIllegalParameter();
            return;
        }
        else
        {
            nCase = 3;					// spaltenweise
            N = nCY;
            M = nRX;
        }
    }
    else
    {
        pMatX = GetNewMat(nCY, nRY, nMatInd2);
        if (!pMatX)
        {
            SetIllegalParameter();
            return;
        }
        for ( ULONG i = 1; i <= nCountY; i++ )
            pMatX->PutDouble((double)i, i-1);
        nCase = 1;
    }
    USHORT nMatInd;
    ScMatrix* pResMat;
    if (nCase == 1)
    {
        if (!bStats)
            pResMat = GetNewMat(2,1,nMatInd);
        else
            pResMat = GetNewMat(2,5,nMatInd);
        if (!pResMat)
        {
            SetIllegalParameter();
            return;
        }
        double fCount   = 0.0;
        double fSumX    = 0.0;
        double fSumSqrX = 0.0;
        double fSumY    = 0.0;
        double fSumSqrY = 0.0;
        double fSumXY   = 0.0;
        double fValX, fValY;
        for (USHORT i = 0; i < nCY; i++)
            for (USHORT j = 0; j < nRY; j++)
            {
                fValX = pMatX->GetDouble(i,j);
                fValY = pMatY->GetDouble(i,j);
                fSumX    += fValX;
                fSumSqrX += fValX * fValX;
                fSumY    += fValY;
                fSumSqrY += fValY * fValY;
                fSumXY   += fValX*fValY;
                fCount++;
            }
        if (fCount < 1.0)
            SetNoValue();
        else
        {
            double f1 = fCount*fSumXY-fSumX*fSumY;
            double fX = fCount*fSumSqrX-fSumX*fSumX;
            double b, m;
            if (bConstant)
            {
                b = fSumY/fCount - f1/fX*fSumX/fCount;
                m = f1/fX;
            }
            else
            {
                b = 0.0;
                m = fSumXY/fSumSqrX;
            }
            pResMat->PutDouble(m, 0, 0);
            pResMat->PutDouble(b, 1, 0);
            if (bStats)
            {
                double fY = fCount*fSumSqrY-fSumY*fSumY;
                double fSyx = fSumSqrY-b*fSumY-m*fSumXY;
                double fR2 = f1*f1/(fX*fY);
                pResMat->PutDouble (fR2, 0, 2);
                if (fCount < 3.0)
                {
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 1 );
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 1 );
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2 );
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
                }
                else
                {
                    pResMat->PutDouble(sqrt(fSyx*fCount/(fX*(fCount-2.0))), 0, 1);
                    pResMat->PutDouble(sqrt(fSyx*fSumSqrX/fX/(fCount-2.0)), 1, 1);
                    pResMat->PutDouble(
                        sqrt((fCount*fSumSqrY - fSumY*fSumY - f1*f1/fX)/
                             (fCount*(fCount-2.0))), 1, 2);
                    if (fR2 == 1.0)
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
                    else
                        pResMat->PutDouble(fR2*(fCount-2.0)/(1.0-fR2), 0, 3);
                }
                pResMat->PutDouble(((double)(nCY*nRY))-2.0, 1, 3);
                pResMat->PutDouble(fY/fCount-fSyx, 0, 4);
                pResMat->PutDouble(fSyx, 1, 4);
            }
        }
    }
    else
    {
        USHORT nMatInd10, nMatInd12, nMatInd13, i, j, k;
        if (!bStats)
            pResMat = GetNewMat(M+1,1,nMatInd);
        else
            pResMat = GetNewMat(M+1,5,nMatInd);
        if (!pResMat)
        {
            SetIllegalParameter();
            return;
        }
        BOOL bVariancesOk = TRUE;
        ScMatrix* pQ = GetNewMat(M+1, M+2, nMatInd10);
        ScMatrix* pE = GetNewMat(M+2, 1, nMatInd12);
        ScMatrix* pV = GetNewMat(M+1, 1, nMatInd13);
        pE->PutDouble(0.0, M+1);
        pQ->FillDouble(0.0, 0, 0, M, M+1);
        if (nCase == 2)
        {
            for (k = 0; k < N; k++)
            {
                double Yk = pMatY->GetDouble(k);
                pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
                double sumYk = pQ->GetDouble(0, M+1) + Yk;
                pQ->PutDouble( sumYk, 0, M+1 );
                pE->PutDouble( sumYk, 0 );
                for (i = 0; i < M; i++)
                {
                    double Xik = pMatX->GetDouble(i,k);
                    double sumXik = pQ->GetDouble(0, i+1) + Xik;
                    pQ->PutDouble( sumXik, 0, i+1);
                    pQ->PutDouble( sumXik, i+1, 0);
                    double sumXikYk = pQ->GetDouble(i+1, M+1) + Xik * Yk;
                    pQ->PutDouble( sumXikYk, i+1, M+1);
                    pE->PutDouble( sumXikYk, i+1);
                    for (j = i; j < M; j++)
                    {
                        double sumXikXjk = pQ->GetDouble(j+1, i+1) +
                             Xik * pMatX->GetDouble(j,k);
                        pQ->PutDouble( sumXikXjk, j+1, i+1);
                        pQ->PutDouble( sumXikXjk, i+1, j+1);
                    }
                }
            }
        }
        else
        {
            for (k = 0; k < N; k++)
            {
                double Yk = pMatY->GetDouble(k);
                pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
                double sumYk = pQ->GetDouble(0, M+1) + Yk;
                pQ->PutDouble( sumYk, 0, M+1 );
                pE->PutDouble( sumYk, 0 );
                for (i = 0; i < M; i++)
                {
                    double Xki = pMatX->GetDouble(k,i);
                    double sumXki = pQ->GetDouble(0, i+1) + Xki;
                    pQ->PutDouble( sumXki, 0, i+1);
                    pQ->PutDouble( sumXki, i+1, 0);
                    double sumXkiYk = pQ->GetDouble(i+1, M+1) + Xki * Yk;
                    pQ->PutDouble( sumXkiYk, i+1, M+1);
                    pE->PutDouble( sumXkiYk, i+1);
                    for (j = i; j < M; j++)
                    {
                        double sumXkiXkj = pQ->GetDouble(j+1, i+1) +
                             Xki * pMatX->GetDouble(k,j);
                        pQ->PutDouble( sumXkiXkj, j+1, i+1);
                        pQ->PutDouble( sumXkiXkj, i+1, j+1);
                    }
                }
            }
        }
        pQ->PutDouble((double)N, 0, 0);
        if (bConstant)
        {
            USHORT S, L;
            for (S = 0; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    delete pV;
                    ResetNewMat(nMatInd13);
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 0; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 0; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 0; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 0; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
            }
        }
        else
        {
            USHORT S, L;
            for (S = 1; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    delete pV;
                    ResetNewMat(nMatInd13);
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 1; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 1; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 1; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 1; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
                pQ->PutDouble(0.0, 0, M+1);		// Konstante b
            }
        }
        // mn ... m1, b
        for (i = 0; i < M+1; i++)
            pResMat->PutDouble(pQ->GetDouble(M-i,M+1), i, 0);
        if (bStats)
        {
            // pE[0]	:= Sigma i=1...n (Yi)
            // pE[k]	:= Sigma i=1...n (Xki*Yi)
            // pE[M+1]	:= Sigma i=1...n (Yi**2)
            // pQ[0,M+1]:= B
            // pQ[k,M+1]:= Mk
            double fSQR, fSQT, fSQE;
            fSQT = pE->GetDouble(M+1)
                - pE->GetDouble(0) * pE->GetDouble(0) / (double)N;
            fSQR = pE->GetDouble(M+1);
            for (i = 0; i < M+1; i++)
                fSQR -= pQ->GetDouble(i, M+1) * pE->GetDouble(i);
            fSQE = fSQT-fSQR;
            // r2 (Bestimmtheitsmass, 0...1)
            if (fSQT == 0.0)
                pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 2);
            else
                pResMat->PutDouble (fSQE/fSQT, 0, 2);
            // ssReg (Regressions-Quadratsumme)
            pResMat->PutDouble(fSQE, 0, 4);
            // ssResid (Residual-Quadratsumme, Summe der Abweichungsquadrate)
            pResMat->PutDouble(fSQR, 1, 4);
            for (i = 2; i < 5; i++)
                for (j = 2; j < M+1; j++)
                    pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), j, i);
            if (bConstant)
            {
                if (N-M-1 == 0)
                {
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
                    for (i = 0; i < M+1; i++)
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
                }
                else
                {
                    double fSE2 = fSQR/(N-M-1);
                    // sey (Standardfehler des Schaetzwertes y)
                    pResMat->PutDouble(sqrt(fSE2), 1, 2);
                    // sen...se1 (Standardfehler der Koeffizienten mn...m1)
                    // seb (Standardfehler der Konstanten b)
                    if ( RGetVariances( pV, pMatX, M+1, N, nCase != 2, FALSE ) )
                    {
                        for (i = 0; i < M+1; i++)
                            pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i, 1 );
                    }
                    else
                    {
                        for (i = 0; i < M+1; i++)
                            pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
                    }
                }
                // F (F-Statistik)
                if (fSQR == 0.0)
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
                else
                    pResMat->PutDouble(((double)(N-M-1))*fSQE/fSQR/((double)M),0, 3);
                // df (Freiheitsgrad)
                pResMat->PutDouble(((double)(N-M-1)), 1, 3);
            }
            else
            {
                if (N-M == 0)
                {
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
                    for (i = 0; i < M+1; i++)
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
                }
                else
                {
                    double fSE2 = fSQR/(N-M);
                    pResMat->PutDouble(sqrt(fSE2), 1, 2);
                    if ( RGetVariances( pV, pMatX, M, N, nCase != 2, TRUE ) )
                    {
                        for (i = 0; i < M; i++)
                            pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i-1, 1 );
                        pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), M, 1);
                    }
                    else
                    {
                        for (i = 0; i < M+1; i++)
                            pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
                    }
                }
                if (fSQR == 0.0)
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
                else
                    pResMat->PutDouble(((double)(N-M))*fSQE/fSQR/((double)M),0, 3);
                pResMat->PutDouble(((double)(N-M)), 1, 3);
            }
        }
        delete pQ;
        delete pE;
        delete pV;
        ResetNewMat(nMatInd13);
        ResetNewMat(nMatInd12);
        ResetNewMat(nMatInd10);
    }
    PushMatrix(pResMat);
    nRetMat = nMatInd;
}

void ScInterpreter::ScRKP()
{
    BYTE nParamCount = GetByte();
    if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
        return;
    BOOL bConstant, bStats;
    if (nParamCount == 4)
        bStats = GetBool();
    else
        bStats = FALSE;
    if (nParamCount >= 3)
        bConstant = GetBool();
    else
        bConstant = TRUE;
    USHORT nMatInd1, nMatInd2;
    ScMatrix* pMatX;
    ScMatrix* pMatY;
    if (nParamCount >= 2)
        pMatX = GetMatrix(nMatInd2);
    else
        pMatX = NULL;
    pMatY = GetMatrix(nMatInd1);
    if (!pMatY)
    {
        SetIllegalParameter();
        return;
    }
    BYTE nCase;							// 1 = normal, 2,3 = mehrfach
    USHORT nCX, nRX, nCY, nRY, M, N;
    pMatY->GetDimensions(nCY, nRY);
    ULONG nCountY = (ULONG) nCY * nRY;
    ULONG i;
    for (i = 0; i < nCountY; i++)
        if (!pMatY->IsValue(i))
        {
            SetIllegalArgument();
            return;
        }
    for (i = 0; i < nCountY; i++)
    {
        if (pMatY->GetDouble(i) <= 0.0)
        {
            SetIllegalArgument();
            return;
        }
        else
            pMatY->PutDouble(log(pMatY->GetDouble(i)), i);
    }
    if (pMatX)
    {
        pMatX->GetDimensions(nCX, nRX);
        ULONG nCountX = (ULONG) nCX * nRX;
        for (i = 0; i < nCountX; i++)
            if (!pMatX->IsValue(i))
            {
                SetIllegalArgument();
                return;
            }
        if (nCX == nCY && nRX == nRY)
            nCase = 1;					// einfache Regression
        else if (nCY != 1 && nRY != 1)
        {
            SetIllegalParameter();
            return;
        }
        else if (nCY == 1)
        {
            if (nRX != nRY)
            {
                SetIllegalParameter();
                return;
            }
            else
            {
                nCase = 2;				// zeilenweise
                N = nRY;
                M = nCX;
            }
        }
        else if (nCX != nCY)
        {
            SetIllegalParameter();
            return;
        }
        else
        {
            nCase = 3;					// spaltenweise
            N = nCY;
            M = nRX;
        }
    }
    else
    {
        pMatX = GetNewMat(nCY, nRY, nMatInd2);
        if (!pMatX)
        {
            SetIllegalParameter();
            return;
        }
        for ( ULONG i = 1; i <= nCountY; i++ )
            pMatX->PutDouble((double)i, i-1);
        nCase = 1;
    }
    USHORT nMatInd;
    ScMatrix* pResMat;
    if (nCase == 1)
    {
        if (!bStats)
            pResMat = GetNewMat(2,1,nMatInd);
        else
            pResMat = GetNewMat(2,5,nMatInd);
        if (!pResMat)
        {
            SetIllegalParameter();
            return;
        }
        double fCount   = 0.0;
        double fSumX    = 0.0;
        double fSumSqrX = 0.0;
        double fSumY    = 0.0;
        double fSumSqrY = 0.0;
        double fSumXY   = 0.0;
        double fValX, fValY;
        for (USHORT i = 0; i < nCY; i++)
            for (USHORT j = 0; j < nRY; j++)
            {
                fValX = pMatX->GetDouble(i,j);
                fValY = pMatY->GetDouble(i,j);
                fSumX    += fValX;
                fSumSqrX += fValX * fValX;
                fSumY    += fValY;
                fSumSqrY += fValY * fValY;
                fSumXY   += fValX*fValY;
                fCount++;
            }
        if (fCount < 1.0)
            SetNoValue();
        else
        {
            double f1 = fCount*fSumXY-fSumX*fSumY;
            double fX = fCount*fSumSqrX-fSumX*fSumX;
            double b, m;
            if (bConstant)
            {
                b = fSumY/fCount - f1/fX*fSumX/fCount;
                m = f1/fX;
            }
            else
            {
                b = 0.0;
                m = fSumXY/fSumSqrX;
            }
            pResMat->PutDouble(exp(m), 0, 0);
            pResMat->PutDouble(exp(b), 1, 0);
            if (bStats)
            {
                double fY = fCount*fSumSqrY-fSumY*fSumY;
                double fSyx = fSumSqrY-b*fSumY-m*fSumXY;
                double fR2 = f1*f1/(fX*fY);
                pResMat->PutDouble (fR2, 0, 2);
                if (fCount < 3.0)
                {
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 1 );
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 1 );
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2 );
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
                }
                else
                {
                    pResMat->PutDouble(sqrt(fSyx*fCount/(fX*(fCount-2.0))), 0, 1);
                    pResMat->PutDouble(sqrt(fSyx*fSumSqrX/fX/(fCount-2.0)), 1, 1);
                    pResMat->PutDouble(
                        sqrt((fCount*fSumSqrY - fSumY*fSumY - f1*f1/fX)/
                             (fCount*(fCount-2.0))), 1, 2);
                    if (fR2 == 1.0)
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3 );
                    else
                        pResMat->PutDouble(fR2*(fCount-2.0)/(1.0-fR2), 0, 3);
                }
                pResMat->PutDouble(((double)(nCY*nRY))-2.0, 1, 3);
                pResMat->PutDouble(fY/fCount-fSyx, 0, 4);
                pResMat->PutDouble(fSyx, 1, 4);
            }
        }
    }
    else
    {
        USHORT nMatInd10, nMatInd12, nMatInd13, i, j, k;
        if (!bStats)
            pResMat = GetNewMat(M+1,1,nMatInd);
        else
            pResMat = GetNewMat(M+1,5,nMatInd);
        if (!pResMat)
        {
            SetIllegalParameter();
            return;
        }
        ScMatrix* pQ = GetNewMat(M+1, M+2, nMatInd10);
        ScMatrix* pE = GetNewMat(M+2, 1, nMatInd12);
        ScMatrix* pV = GetNewMat(M+1, 1, nMatInd13);
        pE->PutDouble(0.0, M+1);
        pQ->FillDouble(0.0, 0, 0, M, M+1);
        if (nCase == 2)
        {
            for (k = 0; k < N; k++)
            {
                double Yk = pMatY->GetDouble(k);
                pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
                double sumYk = pQ->GetDouble(0, M+1) + Yk;
                pQ->PutDouble( sumYk, 0, M+1 );
                pE->PutDouble( sumYk, 0 );
                for (i = 0; i < M; i++)
                {
                    double Xik = pMatX->GetDouble(i,k);
                    double sumXik = pQ->GetDouble(0, i+1) + Xik;
                    pQ->PutDouble( sumXik, 0, i+1);
                    pQ->PutDouble( sumXik, i+1, 0);
                    double sumXikYk = pQ->GetDouble(i+1, M+1) + Xik * Yk;
                    pQ->PutDouble( sumXikYk, i+1, M+1);
                    pE->PutDouble( sumXikYk, i+1);
                    for (j = i; j < M; j++)
                    {
                        double sumXikXjk = pQ->GetDouble(j+1, i+1) +
                             Xik * pMatX->GetDouble(j,k);
                        pQ->PutDouble( sumXikXjk, j+1, i+1);
                        pQ->PutDouble( sumXikXjk, i+1, j+1);
                    }
                }
            }
        }
        else
        {
            for (k = 0; k < N; k++)
            {
                double Yk = pMatY->GetDouble(k);
                pE->PutDouble( pE->GetDouble(M+1)+Yk*Yk, M+1 );
                double sumYk = pQ->GetDouble(0, M+1) + Yk;
                pQ->PutDouble( sumYk, 0, M+1 );
                pE->PutDouble( sumYk, 0 );
                for (i = 0; i < M; i++)
                {
                    double Xki = pMatX->GetDouble(k,i);
                    double sumXki = pQ->GetDouble(0, i+1) + Xki;
                    pQ->PutDouble( sumXki, 0, i+1);
                    pQ->PutDouble( sumXki, i+1, 0);
                    double sumXkiYk = pQ->GetDouble(i+1, M+1) + Xki * Yk;
                    pQ->PutDouble( sumXkiYk, i+1, M+1);
                    pE->PutDouble( sumXkiYk, i+1);
                    for (j = i; j < M; j++)
                    {
                        double sumXkiXkj = pQ->GetDouble(j+1, i+1) +
                             Xki * pMatX->GetDouble(k,j);
                        pQ->PutDouble( sumXkiXkj, j+1, i+1);
                        pQ->PutDouble( sumXkiXkj, i+1, j+1);
                    }
                }
            }
        }
        pQ->PutDouble((double)N, 0, 0);
        if (bConstant)
        {
            USHORT S, L;
            for (S = 0; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    delete pV;
                    ResetNewMat(nMatInd13);
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 0; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 0; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 0; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 0; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
            }
        }
        else
        {
            USHORT S, L;
            for (S = 1; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    delete pV;
                    ResetNewMat(nMatInd13);
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 1; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 1; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 1; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 1; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
                pQ->PutDouble(0.0, 0, M+1);
            }
        }
        for (i = 0; i < M+1; i++)
            pResMat->PutDouble(exp(pQ->GetDouble(M-i,M+1)), i, 0);
        if (bStats)
        {
            double fSQR, fSQT, fSQE;
            fSQT = pE->GetDouble(M+1)-pE->GetDouble(0)*pE->GetDouble(0)/((double)N);
            fSQR = pE->GetDouble(M+1);
            for (i = 0; i < M+1; i++)
                fSQR += -pQ->GetDouble(i, M+1)*pE->GetDouble(i);
            fSQE = fSQT-fSQR;
            if (fSQT == 0.0)
                pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 2);
            else
                pResMat->PutDouble (fSQE/fSQT, 0, 2);
            pResMat->PutDouble(fSQE, 0, 4);
            pResMat->PutDouble(fSQR, 1, 4);
            for (i = 2; i < 5; i++)
                for (j = 2; j < M+1; j++)
                    pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), j, i);
            if (bConstant)
            {
                if (N-M-1 == 0)
                {
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
                    for (i = 0; i < M+1; i++)
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
                }
                else
                {
                    double fSE2 = fSQR/(N-M-1);
                    pResMat->PutDouble(sqrt(fSE2), 1, 2);
                    if ( RGetVariances( pV, pMatX, M+1, N, nCase != 2, FALSE ) )
                    {
                        for (i = 0; i < M+1; i++)
                            pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i, 1 );
                    }
                    else
                    {
                        for (i = 0; i < M+1; i++)
                            pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
                    }
                }
                if (fSQR == 0.0)
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
                else
                    pResMat->PutDouble(((double)(N-M-1))*fSQE/fSQR/((double)M),0, 3);
                pResMat->PutDouble(((double)(N-M-1)), 1, 3);
            }
            else
            {
                if (N-M == 0)
                {
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 1, 2);
                    for (i = 0; i < M+1; i++)
                        pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), i, 1);
                }
                else
                {
                    double fSE2 = fSQR/(N-M);
                    pResMat->PutDouble(sqrt(fSE2), 1, 2);
                    if ( RGetVariances( pV, pMatX, M, N, nCase != 2, TRUE ) )
                    {
                        for (i = 0; i < M; i++)
                            pResMat->PutDouble( sqrt(fSE2 * pV->GetDouble(i)), M-i-1, 1 );
                        pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), M, 1);
                    }
                    else
                    {
                        for (i = 0; i < M+1; i++)
                            pResMat->PutString(ScGlobal::GetRscString(STR_NV_STR), i, 1);
                    }
                }
                if (fSQR == 0.0)
                    pResMat->PutString(ScGlobal::GetRscString(STR_NO_VALUE), 0, 3);
                else
                    pResMat->PutDouble(((double)(N-M))*fSQE/fSQR/((double)M),0, 3);
                pResMat->PutDouble(((double)(N-M)), 1, 3);
            }
        }
        delete pQ;
        delete pE;
        delete pV;
        ResetNewMat(nMatInd13);
        ResetNewMat(nMatInd12);
        ResetNewMat(nMatInd10);
    }
    PushMatrix(pResMat);
    nRetMat = nMatInd;
}


void ScInterpreter::ScTrend()
{
    BYTE nParamCount = GetByte();
    if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
        return;
    BOOL bConstant;
    if (nParamCount == 4)
        bConstant = GetBool();
    else
        bConstant = TRUE;
    USHORT nMatInd1, nMatInd2, nMatInd3;
    ScMatrix* pMatX;
    ScMatrix* pMatY;
    ScMatrix* pMatNewX;
    if (nParamCount >= 3)
        pMatNewX = GetMatrix(nMatInd3);
    else
        pMatNewX = NULL;
    if (nParamCount >= 2)
        pMatX = GetMatrix(nMatInd2);
    else
        pMatX = NULL;
    pMatY = GetMatrix(nMatInd1);
    if (!pMatY)
    {
        SetIllegalParameter();
        return;
    }
    BYTE nCase;							// 1 = normal, 2,3 = mehrfach
    USHORT nCX, nRX, nCY, nRY, M, N;
    pMatY->GetDimensions(nCY, nRY);
    ULONG nCountY = (ULONG) nCY * nRY;
    ULONG i;
    for (i = 0; i < nCountY; i++)
        if (!pMatY->IsValue(i))
        {
            SetIllegalArgument();
            return;
        }
    if (pMatX)
    {
        pMatX->GetDimensions(nCX, nRX);
        ULONG nCountX = (ULONG) nCX * nRX;
        for (i = 0; i < nCountX; i++)
            if (!pMatX->IsValue(i))
            {
                SetIllegalArgument();
                return;
            }
        if (nCX == nCY && nRX == nRY)
            nCase = 1;					// einfache Regression
        else if (nCY != 1 && nRY != 1)
        {
            SetIllegalParameter();
            return;
        }
        else if (nCY == 1)
        {
            if (nRX != nRY)
            {
                SetIllegalParameter();
                return;
            }
            else
            {
                nCase = 2;				// zeilenweise
                N = nRY;
                M = nCX;
            }
        }
        else if (nCX != nCY)
        {
            SetIllegalParameter();
            return;
        }
        else
        {
            nCase = 3;					// spaltenweise
            N = nCY;
            M = nRX;
        }
    }
    else
    {
        pMatX = GetNewMat(nCY, nRY, nMatInd2);
        nCX = nCY;
        nRX = nRY;
        if (!pMatX)
        {
            SetIllegalParameter();
            return;
        }
        for (i = 1; i <= nCountY; i++)
            pMatX->PutDouble((double)i, i-1);
        nCase = 1;
    }
    USHORT nCXN, nRXN;
    ULONG nCountXN;
    if (!pMatNewX)
    {
        nCXN = nCX;
        nRXN = nRX;
        nCountXN = (ULONG) nCXN * nRXN;
        pMatNewX = pMatX;
    }
    else
    {
        pMatNewX->GetDimensions(nCXN, nRXN);
        if ((nCase == 2 && nCX != nCXN) || (nCase == 3 && nRX != nRXN))
        {
            SetIllegalArgument();
            return;
        }
        nCountXN = (ULONG) nCXN * nRXN;
        for ( ULONG i = 0; i < nCountXN; i++ )
            if (!pMatNewX->IsValue(i))
            {
                SetIllegalArgument();
                return;
            }
    }
    USHORT nMatInd;
    ScMatrix* pResMat;
    if (nCase == 1)
    {
        double fCount   = 0.0;
        double fSumX    = 0.0;
        double fSumSqrX = 0.0;
        double fSumY    = 0.0;
        double fSumSqrY = 0.0;
        double fSumXY   = 0.0;
        double fValX, fValY;
        for (USHORT i = 0; i < nCY; i++)
            for (USHORT j = 0; j < nRY; j++)
            {
                fValX = pMatX->GetDouble(i,j);
                fValY = pMatY->GetDouble(i,j);
                fSumX    += fValX;
                fSumSqrX += fValX * fValX;
                fSumY    += fValY;
                fSumSqrY += fValY * fValY;
                fSumXY   += fValX*fValY;
                fCount++;
            }
        if (fCount < 1.0)
        {
            SetNoValue();
            return;
        }
        else
        {
            double f1 = fCount*fSumXY-fSumX*fSumY;
            double fX = fCount*fSumSqrX-fSumX*fSumX;
            double b, m;
            if (bConstant)
            {
                b = fSumY/fCount - f1/fX*fSumX/fCount;
                m = f1/fX;
            }
            else
            {
                b = 0.0;
                m = fSumXY/fSumSqrX;
            }
            pResMat = GetNewMat(nCXN, nRXN, nMatInd);
            if (!pResMat)
            {
                SetIllegalParameter();
                return;
            }
            for (i = 0; i < nCountXN; i++)
                pResMat->PutDouble(pMatNewX->GetDouble(i)*m+b, i);
        }
    }
    else
    {
        USHORT nMatInd10, nMatInd12, i, j, k;
        ScMatrix* pQ = GetNewMat(M+1, M+2, nMatInd10);
        ScMatrix* pE = GetNewMat(M+2, 1, nMatInd12);
        pE->PutDouble(0.0, M+1);
        pQ->FillDouble(0.0, 0, 0, M, M+1);
        if (nCase == 2)
        {
            for (k = 0; k < N; k++)
            {
                pE->PutDouble(
                    pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
                pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0,	M+1);
                pE->PutDouble(pQ->GetDouble(0, M+1), 0);
                for (i = 0; i < M; i++)
                {
                    pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(i,k), 0, i+1);
                    pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
                    pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
                             pMatX->GetDouble(i,k)*pMatY->GetDouble(k), i+1, M+1);
                    pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
                    for (j = i; j < M; j++)
                    {
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
                             pMatX->GetDouble(i,k)*pMatX->GetDouble(j,k), j+1, i+1);
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
                    }
                }
            }
        }
        else
        {
            for (k = 0; k < N; k++)
            {
                pE->PutDouble(
                    pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
                pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0,	M+1);
                pE->PutDouble(pQ->GetDouble(0, M+1), 0);
                for (i = 0; i < M; i++)
                {
                    pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(k,i), 0, i+1);
                    pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
                    pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
                             pMatX->GetDouble(k,i)*pMatY->GetDouble(k), i+1, M+1);
                    pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
                    for (j = i; j < M; j++)
                    {
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
                             pMatX->GetDouble(k, i)*pMatX->GetDouble(k, j), j+1, i+1);
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
                    }
                }
            }
        }
        pQ->PutDouble((double)N, 0, 0);
        if (bConstant)
        {
            USHORT S, L;
            for (S = 0; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 0; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 0; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 0; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 0; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
            }
        }
        else
        {
            USHORT S, L;
            for (S = 1; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 1; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 1; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 1; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 1; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
                pQ->PutDouble(0.0, 0, M+1);
            }
        }
        if (nCase == 2)
        {
            pResMat = GetNewMat(1, nRXN, nMatInd);
            if (!pResMat)
            {
                SetIllegalParameter();
                return;
            }
            double fVal;
            for (i = 0; i < nRXN; i++)
            {
                fVal = pQ->GetDouble(0, M+1);
                for (j = 0; j < M; j++)
                    fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(j, i);
                pResMat->PutDouble(fVal, i);
            }
        }
        else
        {
            pResMat = GetNewMat(nCXN, 1, nMatInd);
            if (!pResMat)
            {
                SetIllegalParameter();
                return;
            }
            double fVal;
            for (i = 0; i < nCXN; i++)
            {
                fVal = pQ->GetDouble(0, M+1);
                for (j = 0; j < M; j++)
                    fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(i, j);
                pResMat->PutDouble(fVal, i);
            }
        }
        delete pQ;
        delete pE;
        ResetNewMat(nMatInd12);
        ResetNewMat(nMatInd10);
    }
    PushMatrix(pResMat);
    nRetMat = nMatInd;
}

void ScInterpreter::ScGrowth()
{
    BYTE nParamCount = GetByte();
    if ( !MustHaveParamCount( nParamCount, 1, 4 ) )
        return;
    BOOL bConstant;
    if (nParamCount == 4)
        bConstant = GetBool();
    else
        bConstant = TRUE;
    USHORT nMatInd1, nMatInd2, nMatInd3;
    ScMatrix* pMatX;
    ScMatrix* pMatY;
    ScMatrix* pMatNewX;
    if (nParamCount >= 3)
        pMatNewX = GetMatrix(nMatInd3);
    else
        pMatNewX = NULL;
    if (nParamCount >= 2)
        pMatX = GetMatrix(nMatInd2);
    else
        pMatX = NULL;
    pMatY = GetMatrix(nMatInd1);
    if (!pMatY)
    {
        SetIllegalParameter();
        return;
    }
    BYTE nCase;							// 1 = normal, 2,3 = mehrfach
    USHORT nCX, nRX, nCY, nRY, M, N;
    pMatY->GetDimensions(nCY, nRY);
    ULONG nCountY = (ULONG) nCY * nRY;
    ULONG i;
    for (i = 0; i < nCountY; i++)
        if (!pMatY->IsValue(i))
        {
            SetIllegalArgument();
            return;
        }
    for (i = 0; i < nCountY; i++)
    {
        if (pMatY->GetDouble(i) <= 0.0)
        {
            SetIllegalArgument();
            return;
        }
        else
            pMatY->PutDouble(log(pMatY->GetDouble(i)), i);
    }
    if (pMatX)
    {
        pMatX->GetDimensions(nCX, nRX);
        ULONG nCountX = (ULONG) nCX * nRX;
        for ( ULONG i = 0; i < nCountX; i++ )
            if (!pMatX->IsValue(i))
            {
                SetIllegalArgument();
                return;
            }
        if (nCX == nCY && nRX == nRY)
            nCase = 1;					// einfache Regression
        else if (nCY != 1 && nRY != 1)
        {
            SetIllegalParameter();
            return;
        }
        else if (nCY == 1)
        {
            if (nRX != nRY)
            {
                SetIllegalParameter();
                return;
            }
            else
            {
                nCase = 2;				// zeilenweise
                N = nRY;
                M = nCX;
            }
        }
        else if (nCX != nCY)
        {
            SetIllegalParameter();
            return;
        }
        else
        {
            nCase = 3;					// spaltenweise
            N = nCY;
            M = nRX;
        }
    }
    else
    {
        pMatX = GetNewMat(nCY, nRY, nMatInd2);
        nCX = nCY;
        nRX = nRY;
        if (!pMatX)
        {
            SetIllegalParameter();
            return;
        }
        for (i = 1; i <= nCountY; i++)
            pMatX->PutDouble((double)i, i-1);
        nCase = 1;
    }
    USHORT nCXN, nRXN;
    ULONG nCountXN;
    if (!pMatNewX)
    {
        nCXN = nCX;
        nRXN = nRX;
        nCountXN = (ULONG) nCXN * nRXN;
        pMatNewX = pMatX;
    }
    else
    {
        pMatNewX->GetDimensions(nCXN, nRXN);
        if ((nCase == 2 && nCX != nCXN) || (nCase == 3 && nRX != nRXN))
        {
            SetIllegalArgument();
            return;
        }
        nCountXN = (ULONG) nCXN * nRXN;
        for ( ULONG i = 0; i < nCountXN; i++ )
            if (!pMatNewX->IsValue(i))
            {
                SetIllegalArgument();
                return;
            }
    }
    USHORT nMatInd;
    ScMatrix* pResMat;
    if (nCase == 1)
    {
        double fCount   = 0.0;
        double fSumX    = 0.0;
        double fSumSqrX = 0.0;
        double fSumY    = 0.0;
        double fSumSqrY = 0.0;
        double fSumXY   = 0.0;
        double fValX, fValY;
        for (USHORT i = 0; i < nCY; i++)
            for (USHORT j = 0; j < nRY; j++)
            {
                fValX = pMatX->GetDouble(i,j);
                fValY = pMatY->GetDouble(i,j);
                fSumX    += fValX;
                fSumSqrX += fValX * fValX;
                fSumY    += fValY;
                fSumSqrY += fValY * fValY;
                fSumXY   += fValX*fValY;
                fCount++;
            }
        if (fCount < 1.0)
        {
            SetNoValue();
            return;
        }
        else
        {
            double f1 = fCount*fSumXY-fSumX*fSumY;
            double fX = fCount*fSumSqrX-fSumX*fSumX;
            double b, m;
            if (bConstant)
            {
                b = fSumY/fCount - f1/fX*fSumX/fCount;
                m = f1/fX;
            }
            else
            {
                b = 0.0;
                m = fSumXY/fSumSqrX;
            }
            pResMat = GetNewMat(nCXN, nRXN, nMatInd);
            if (!pResMat)
            {
                SetIllegalParameter();
                return;
            }
            for (i = 0; i < nCountXN; i++)
                pResMat->PutDouble(exp(pMatNewX->GetDouble(i)*m+b), i);
        }
    }
    else
    {
        USHORT nMatInd10, nMatInd12, i, j, k;
        ScMatrix* pQ = GetNewMat(M+1, M+2, nMatInd10);
        ScMatrix* pE = GetNewMat(M+2, 1, nMatInd12);
        pE->PutDouble(0.0, M+1);
        pQ->FillDouble(0.0, 0, 0, M, M+1);
        if (nCase == 2)
        {
            for (k = 0; k < N; k++)
            {
                pE->PutDouble(
                    pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
                pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0,	M+1);
                pE->PutDouble(pQ->GetDouble(0, M+1), 0);
                for (i = 0; i < M; i++)
                {
                    pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(i,k), 0, i+1);
                    pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
                    pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
                             pMatX->GetDouble(i,k)*pMatY->GetDouble(k), i+1, M+1);
                    pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
                    for (j = i; j < M; j++)
                    {
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
                             pMatX->GetDouble(i,k)*pMatX->GetDouble(j,k), j+1, i+1);
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
                    }
                }
            }
        }
        else
        {
            for (k = 0; k < N; k++)
            {
                pE->PutDouble(
                    pE->GetDouble(M+1)+pMatY->GetDouble(k)*pMatY->GetDouble(k), M+1);
                pQ->PutDouble(pQ->GetDouble(0, M+1) + pMatY->GetDouble(k), 0,	M+1);
                pE->PutDouble(pQ->GetDouble(0, M+1), 0);
                for (i = 0; i < M; i++)
                {
                    pQ->PutDouble(pQ->GetDouble(0, i+1)+pMatX->GetDouble(k,i), 0, i+1);
                    pQ->PutDouble(pQ->GetDouble(0, i+1), i+1, 0);
                    pQ->PutDouble(pQ->GetDouble(i+1, M+1) +
                             pMatX->GetDouble(k,i)*pMatY->GetDouble(k), i+1, M+1);
                    pE->PutDouble(pQ->GetDouble(i+1, M+1), i+1);
                    for (j = i; j < M; j++)
                    {
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1) +
                             pMatX->GetDouble(k, i)*pMatX->GetDouble(k, j), j+1, i+1);
                        pQ->PutDouble(pQ->GetDouble(j+1, i+1), i+1, j+1);
                    }
                }
            }
        }
        pQ->PutDouble((double)N, 0, 0);
        if (bConstant)
        {
            USHORT S, L;
            for (S = 0; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 0; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 0; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 0; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 0; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
            }
        }
        else
        {
            USHORT S, L;
            for (S = 1; S < M+1; S++)
            {
                i = S;
                while (i < M+1 && pQ->GetDouble(i, S) == 0.0)
                    i++;
                if (i >= M+1)
                {
                    SetNoValue();
                    delete pQ;
                    delete pE;
                    ResetNewMat(nMatInd12);
                    ResetNewMat(nMatInd10);
                    return;
                }
                double fVal;
                for (L = 1; L < M+2; L++)
                {
                    fVal = pQ->GetDouble(S, L);
                    pQ->PutDouble(pQ->GetDouble(i, L), S, L);
                    pQ->PutDouble(fVal, i, L);
                }
                fVal = 1.0/pQ->GetDouble(S, S);
                for (L = 1; L < M+2; L++)
                    pQ->PutDouble(pQ->GetDouble(S, L)*fVal, S, L);
                for (i = 1; i < M+1; i++)
                {
                    if (i != S)
                    {
                        fVal = -pQ->GetDouble(i, S);
                        for (L = 1; L < M+2; L++)
                            pQ->PutDouble(
                                pQ->GetDouble(i,L)+fVal*pQ->GetDouble(S,L),i,L);
                    }
                }
                pQ->PutDouble(0.0, 0, M+1);
            }
        }
        if (nCase == 2)
        {
            pResMat = GetNewMat(1, nRXN, nMatInd);
            if (!pResMat)
            {
                SetIllegalParameter();
                return;
            }
            double fVal;
            for (i = 0; i < nRXN; i++)
            {
                fVal = pQ->GetDouble(0, M+1);
                for (j = 0; j < M; j++)
                    fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(j, i);
                pResMat->PutDouble(exp(fVal), i);
            }
        }
        else
        {
            pResMat = GetNewMat(nCXN, 1, nMatInd);
            if (!pResMat)
            {
                SetIllegalParameter();
                return;
            }
            double fVal;
            for (i = 0; i < nCXN; i++)
            {
                fVal = pQ->GetDouble(0, M+1);
                for (j = 0; j < M; j++)
                    fVal += pQ->GetDouble(j+1, M+1)*pMatNewX->GetDouble(i, j);
                pResMat->PutDouble(exp(fVal), i);
            }
        }
        delete pQ;
        delete pE;
        ResetNewMat(nMatInd12);
        ResetNewMat(nMatInd10);
    }
    PushMatrix(pResMat);
    nRetMat = nMatInd;
}

/*N*/ void ScInterpreter::ScMatRef()
/*N*/ {
/*N*/ 	// Falls Deltarefs drin sind...
/*N*/ 	Push( (ScToken&) *pCur );
/*N*/ 	ScAddress aAdr;
/*N*/ 	PopSingleRef( aAdr );
/*N*/ 	ScFormulaCell* pCell = (ScFormulaCell*) GetCell( aAdr );
/*N*/ 	if( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
/*N*/ 	{
/*N*/ 		ScMatrix* pMat;
/*N*/ 		pCell->GetMatrix( &pMat );
/*N*/ 		if( pMat )
/*N*/ 		{
/*N*/ 			USHORT nCl, nRw;
/*N*/ 			pMat->GetDimensions( nCl, nRw );
/*N*/ 			USHORT nC = aPos.Col() - aAdr.Col();
/*N*/ 			USHORT nR = aPos.Row() - aAdr.Row();
/*N*/ 			if (nC < nCl && nR < nRw)
/*N*/ 			{
/*N*/ 				BOOL bIsString;
/*N*/ 				const MatValue* pMatVal = pMat->Get(nC, nR, bIsString);
/*N*/ 				if (bIsString)
/*?*/ 					PushString( pMatVal->GetString() );
/*N*/ 				else
/*N*/ 				{
/*N*/ 					PushDouble(pMatVal->fVal);
/*N*/ 					pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, *pCell );
/*N*/ 					nFuncFmtType = nCurFmtType;
/*N*/ 					nFuncFmtIndex = nCurFmtIndex;
/*N*/ 				}
/*N*/ 			}
/*N*/ 			else
/*?*/ 				SetNV();
/*N*/ 		}
/*N*/ 		else
/*N*/ 		{
/*?*/ 			// Ist gar keine Ergebnis-Matrix, dann bitte den Wert holen!
/*?*/ 			USHORT nErr = pCell->GetErrCode();
/*?*/ 			SetError( nErr );
/*?*/ 			if( pCell->IsValue() )
/*?*/ 				PushDouble( pCell->GetValue() );
/*?*/ 			else
/*?*/ 			{
/*?*/ 				String aVal;
/*?*/ 				pCell->GetString( aVal );
/*?*/ 				PushString( aVal );
/*?*/ 			}
/*?*/ 			pDok->GetNumberFormatInfo( nCurFmtType, nCurFmtIndex, aAdr, *pCell );
/*?*/ 			nFuncFmtType = nCurFmtType;
/*?*/ 			nFuncFmtIndex = nCurFmtIndex;
/*?*/ 		}
/*N*/ 	}
/*N*/ 	else
/*N*/ 		SetError( errNoRef );
/*N*/ }



}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
