Home RSS 2.0 ATOM 1.0  CDF  
 
CodeSegment - Carlos Segura Sanz (blog)
 
Page 1 of 1 in the Excel category

Hace ya algún tiempo que escribí CS-Solver, estos días me he propuesto convertirlo de VBA a VSTO.

CS-Solver es un add-in para Excel que escribí hace algún tiempo, ya que la calculadora que usaba tenía un sistema de resolver ecuaciones muy parecido (PowerOne finance) y sin embargo resolver ecuaciones con Excel era bastante más complicado.

CS-Solver utiliza el método secante para encontrar las raíces de f(x)=0 en un intervalo, este no es tan rápido como el de Newton, pero si más rápido que la bisección ya que acota el intervalo y usa la aproximación más reciente.

A diferencia del método de Newton, no necesitamos calcular la derivada de la función en cada iteración, y que es un proceso más tedioso y requiere cálculo adicional.

Veamos ahora como funciona CS-Solver con un pequeño ejemplo, resolviendo la siguiente ecuación
2^x + 5x = 2

Primero crearemos una celda C2 a la que daremos un nombre en este caso X, esta es la incógnita, en otra celda teclearemos la función, igualando el resultado a 0, quedando la ecuación 2^x+5x-2=0, esta celda la introduciremos como texto.

Ahora desde el menú de CSSolver, seleccionamos resolver ecuación

En donde se nos pide que introduzcamos la celda que contiene la ecuación a resolver, una vez seleccionada la celda que contiene la ecuación C4 pulsamos sobre Aceptar

El resultado aparece en la celda de nombre X que es la incógnita a resolver.

Veamos ahora otras cosas que se puede hacer con CS-Solver. Para ello usaremos la formula del Interés compuesto y calcularemos el Valor Futuro de un Capital invertido al 5% de interés anual durante 3 meses.

Valor Final = Valor Actual * ( 1 + (Interés/12))^Meses

Teclearemos la formula igualada a 0, 0=(vactual*(1+interes))^meses)-vfinal para ello, nombraremos la celda C2 como vfinal, C3 como vactual, C4 como interes y C5 como meses

Si ejecutamos CS-Solver y seleccionamos B7 como la formula a resolver obtendremos el Valor Actual, solucionando la ecuación.

Bien, una vez obtenido el resultado deseamos vemos que 1012,55 no es lo esperado que necesitamos obtener al final de nuestra inversión un total de 1125, así que queremos ver cuanto necesitamos ingresar ahora para poder retirar dentro de 3 meses 1125

Para ello, nos basta con eliminar el contenido de la celda C3, (vactual) e indicar en la celda C2 el importe que deseamos obtener. Nuestra hoja de excel quedaría así.


Bien, no tenemos que tocar nada más tan solo seleccionar CS-Solver e indicar la formula que ya habíamos escrito, B7

CS-Solver comprueba cual es la incógnita de la ecuación, vactual en este caso y comprueba que no tiene valor, así que su objetivo es resolver dicha incógnita.

CS-Solver incorpora también una nueva formula llamada CSSolver con la cual podemos tener en una celda el valor de la incógnita de la ecuación, de este modo se puede tener en una celda =CSSolver(“2*x*sin(x)-5”) para la ecuación 2*x*sin(x)=5 e incluso podemos vincular la formula con una celda =CSSolver(A5)

Estoy pasando el código de VBA a VSTO así que en unos días espero tenerlo terminado. (Excel)

Saturday, July 01, 2006 7:29:27 PM (Hora de verano romance, UTC+02:00)   #    Comments [0]   Excel | Office  | 

No se si lo he comentado alguna vez, pero en el trabajo suelo usar mucho Excel para hacer una gran variedad de cosas, en general mucho de lo que tiene que ver con el área económico financiera (lo terminamos haciendo en Excel).

Muchas de nuestras hojas de cálculo, son planes financieros, estudios de viabilidad, análisis etc. Básicamente estas hojas planifican cobros y pagos ó gastos e ingresos, la cuestión es la planificación, en Excel podemos planificar todo aquello que queramos, es sencillo podemos establecer una fila para cada previsión a realizar y en cada columna podemos poner un periodo (ene, feb, mar…), por último en cada celda (previsión / periodo) el importe de dicha previsión.


El problema se complica un poco cuando el importe de cada previsión no tiene un periodo fijo, sino que este debe establecerse en función de otra variable. Supongamos que tenemos que realizar una previsión entre dos periodos dados (Inicio y Final) y el importe debe ser proporcional al número de periodos.



Como es lógico las formulas se nos van complicando, más y más en función de las condiciones que necesitamos. Con lo que terminamos creando nuestras funciones en VBA para simplificar el proceso.

Function csPDistB(importe As Integer, periodo As Integer, inicio As Integer, fin As Integer)
 
    If (periodo >= inicio) And (periodo <= fin) Then
        csPDistB = importe / ((fin - inicio) + 1)
    End If
    
End Function

Realizaría el mismo trabajo que las formulas vistas. Dándole una vuelta más podemos crear una función matricial para hacer la misma tarea y que automáticamente tome el periodo actual en función del rango en donde se encuentre.

Public Function csPDistB(importe As Variant, primero As Integer, ultimo As Integer) As Variant
    Dim i As Integer
    Dim nPeriodos As Integer
    Dim valor As Double
    ReDim a(0 To Application.Caller.Rows.Count, 0 To Application.Caller.Columns.Count) As Variant
            
    On Error GoTo Handler
    
    nPeriodos = ultimo - primero
    valor = CDbl(importe / (nPeriodos + 1))
            
    For i = 0 To Application.Caller.Columns.Count
        If i + 1 >= primero And i + 1 <= ultimo Then
           a(0, i) = valor
        End If
    Next
        
    csPDistB = a
    Exit Function
Handler:
    csPDistB = CVErr(2015)  'xlErrNum = 2036
End Function

Por último con una pequeñas modificaciones sobre este código podemos crear funciones más complejas para nuestras planificaciones, por ejemplo distribuciones en función de una curva de porcentajes, 25%, 50% y 25% sería el 25% en el primer tercio, el 50% en el segundo tercio y el 25% en el tercer tercio del tiempo.

Public Function csPDistCP(importe As Variant, ParamArray porcentajes()) As Variant
    Dim i As Integer
    Dim nParte As Integer
    Dim p As Integer
    ReDim a(Application.Caller.Columns.Count) As Variant
            
    On Error GoTo Handler
    
    nParte = (UBound(a) + 1) / (UBound(porcentajes) + 1)
    p = -1
    For i = 0 To UBound(a)
      If i Mod Int(nParte) = 0 Then
         If p < UBound(porcentajes) Then
            p = p + 1
         End If
      End If
 
      a(i) = CDbl((importe / nParte) * porcentajes(p))
    Next
        
    csPDistCP = a
    Exit Function
Handler:
    csPDistCP = CVErr(2015)  'xlErrNum = 2036
End Function

Un último ejemplo en donde realizamos previsiones los periodos indicados, el importe proporcional al número de periodos.

 
Public Function csPDistP(importe As Variant, ParamArray periodos()) As Variant
    Dim i As Integer
    Dim nPeriodos As Integer
    Dim valor As Double
    ReDim a(Application.Caller.Columns.Count) As Variant
            
    On Error GoTo Handler
    
    nPeriodos = UBound(periodos)
    valor = CDbl(importe / (nPeriodos + 1))
            
    For i = 0 To nPeriodos
        a(periodos(i)) = valor
    Next
        
    csPDistP = a
    Exit Function
Handler:
    csPDistP = CVErr(2015)  'xlErrNum = 2036
End Function

 

Tuesday, March 28, 2006 12:21:15 AM (Hora de verano romance, UTC+02:00)   #    Comments [0]   Excel  | 

Continuando con el trabajo que estaba realizando para mostrar información del Analisys Services en SharePoint, he realizado un pequeño programa en Excel para exportar las sentencias MDX (Nota: todavía no he visto el editor del SQL2005 y puede que este sea una maravilla, el del SQL2000 sin comentarios), con lo cual puedo usar Excel con una tabla dinámica para diseñar el informe y exportar este para usarlo con el webpart de OLAP que estaba realizando. Usando el contenido del un .dwp podríamos generar un webpart completo para importar en SharePoint.

Este ejemplo generará un archivo XML con la definición del informe con esta sintaxis.

<?xml version="1.0" encoding="utf-8"?>
<informe>
  <nombre>Informe de Prueba</nombre>
  <descripcion>Informe de ventas de la base de datos FoodMart 2000</descripcion>
  <conexion>
   OLEDB;Provider=MSOLAP.2;Persist Security Info=True;Data Source=srvdatos;Initial Catalog=FoodMart 2000;
   Client Cache Size=25;Auto Synch Period=10000
  </conexion>
  <mdx>
    <![CDATA[ 
    SELECT NON EMPTY HIERARCHIZE({DrillDownLevel({[Product].[All Products]})}) 
    DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON COLUMNS , 
              NON EMPTY HIERARCHIZE({DrillDownMember(
              {{DrillDownMember({DrillDownLevel({[Customers].[All Customers]})}, 
              {[Customers].[All Customers].[USA]})}}, {[Customers].[All Customers].[USA].[CA]})}) 
              DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON ROWS  
              FROM [Warehouse and Sales] WHERE ([Measures].[Sales Count])
   ]]>
   </mdx>
</informe>

Pasos para hacer nuestro diseñador de informes.

1.- Abrir excel
2.- Crear un informe de tabla dinámica usando el asistente de excel
3.- Configurar el informe a nuestro gusto
3.- Llamar a la macro de exportar informe (yo le he hecho un bonito formulario ...)

Sub ExportaXML(sNombre As String, sDesc As String)
    Dim xmlDoc As DOMDocument
    Dim xmlNode As IXMLDOMNode
    Dim xmlAttribute As IXMLDOMAttribute
    Dim xmlInforme As IXMLDOMNode
    Dim xmlPi As IXMLDOMProcessingInstruction
    Set xmlDoc = New DOMDocument
    Dim xmlText As IXMLDOMText
    Dim sArchivo
    
    sArchivo = Application.GetSaveAsFilename("", "Archivo MDX,(*.xml)", , "Archivo MDX en XML")
    If sArchivo <> False Then
    
        Set xmlPi = xmlDoc.createProcessingInstruction("xml", "version=""1.0""")
        Set xmlNode = xmlDoc.appendChild(xmlPi)
        
        Set xmlInforme = xmlDoc.createElement("informe")
        
        Set xmlNode = xmlDoc.appendChild(xmlInforme)
    
        Set xmlNode = xmlDoc.createElement("nombre")
        Set xmlText = xmlNode.appendChild(xmlDoc.createTextNode(sNombre))
        Set xmlNode = xmlInforme.appendChild(xmlNode)
        
        Set xmlNode = xmlDoc.createElement("descripcion")
        Set xmlText = xmlNode.appendChild(xmlDoc.createTextNode(sDesc))
        Set xmlNode = xmlInforme.appendChild(xmlNode)
    
        Set xmlNode = xmlDoc.createElement("conexion")
        Set xmlText = xmlNode.appendChild(xmlDoc.createTextNode(ActiveSheet.PivotTables(1).PivotCache.Connection))
        Set xmlNode = xmlInforme.appendChild(xmlNode)
    
        Set xmlNode = xmlDoc.createElement("mdx")
        Set xmlText = xmlNode.appendChild(xmlDoc.createTextNode(ActiveSheet.PivotTables(1).MDX))
        Set xmlNode = xmlInforme.appendChild(xmlNode)
        
        xmlDoc.Save (sArchivo)
    End If
        
End Sub
Monday, February 20, 2006 8:05:55 PM (Hora estándar romance, UTC+01:00)   #    Comments [0]   Excel | SharePoint-es  | 

Page 1 of 1 in the Excel category

Copyright © 2008 Carlos Segura. All rights reserved.