Rompecabezas malditos: ¿Como medir el tiempo con dos mechas?

fuse blackmatch

Imaginese que tiene dos mechas; Usted sabe que cada una de ellas tarda en quemarse 30 minutos; Usted no tiene un reloj y le piden que diga como puede medir 45 minutos utilizando las dos mechas. También le dicen que las mechas se queman de manera desigual, por lo que quizas %75 de una de ellas se puede quemar en los primeros 5 minutos y el resto en lo que queda de la hora (por ejemplo).

Pienselo un poco y después siga leyendo, este es un problema clásico, hay muchas variaciones.

Solución: Nnecesitamos para medir 45 minutos. 45 minutos es lo mismo que 1 cuerda + 1/2 cuerda = 30 minutos + 15 minutos. Eso significa que quemamos toda una de las cuerdas y medimos 30 minutos, pero para medir los otros 15 minutos no podemos cortar la segunda cuerda en dos, ya que las mechas se queman de manera desigual. Pero no dicen nada de encender la otra mecha por ambos lados, lo cual garantizaría que se queme en 15 minutos. Es decir que la solución es quemar una de las mechas normalmente para luego enseguida quemar la otra mecha por ambos lados.

¿Divertido, no es así? 😀

Rompecabezas malditos: ¡El barco pirata!

Shark Puzzle

Les tengo un rompecabezas para ver si lo pueden resolver:

Existen dos islas, “A” y “B”. Ambas islas están separadas por mar, infestado de tiburones y solamente existe un barco pirata que las comunica a las dos. En la isla A hay un naufrago el cual tiene las siguientes cosas: Una llave, un candado, un cofre y un mensaje. En la isla B hay otro naufrago y este tiene un candado y una llave.

La persona que vive en la isla A quiere enviarle un mensaje a la persona en la isla B y la única forma de hacerlo es usando el barco pirata, el cual no tratará de robarse el cofre si está vacio o si esta cerrado con llave.

Más detalles:

  • Cada llave abre su respectivo candado.
  • Usted puede pasar el cofre cuantas veces quiera entre ambas islas.
  • El cofre es indestructible
  • Si usted pasa cualquier otra cosa que el cofre, el pirata se la va a robar
  • Si usted mete algo en el cofre y no lo cierra, el pirata lo va a abrir y se lo va a robar.

Este problema sale en entrevistas de trabajo. Pienselo un poco y si aún esta’trancado, siga leyendo para darle un par de pistas.

Pistas:

  • ¿Que puede hacer A al principio? ¿Y que haría B?
  • Piense, como funciona la criptografía asimetrica (como PGP).

No siga leyendo e intentelo.

¿Ya se cansó?. Bueno, no lo culpo ya que este es un rompecabezas dificil. La clave aqui es que usted puede ponerle más de dos candados en un momento dado al cofre. Mire la solución algoritmica:

  1. A mete el sobre en el cofre, lo cierra, le pone el candado y lo cierra y se queda con su llave.
  2. El pirata recoge el cofre, pero como está cerrado no lo puede abrir. Fastidiado, lo deja en la orilla de la playa B en donde B lo recibe
  3. B no puede abrir el cofre porque su llave no funciona con el candado que tiene puesto, así que este le pone su candado también y se queda con su llave. Ahora el cofre tiene dos candados (A y B)
  4. El pirata ve el cofre de nuevo y se excita. Trata de abrirlo y no puede (tiene dos candados) y lo deja en la playa A.
  5. El naufrago en A ve el cofre y le quita su candado y espera por el pirata. Ahora sólo el candado de B está puesto en el cofre.
  6. El pirata vuelve a tomar el cofre, lo trata de abrir de nuevo (sin exito) y deja el cofre en B nuevamente.
  7. El naufrago en B recibe el cofre con su candado, lo abre y lee el mensaje. A lo invita a comer paella de tiburón 🙂
  8. El pirata decide dejar de robar cofres y en vez de eso sigue los pasos de Johnny Depp y hace “Pirates of the Caribean III“. Es un exito.

Espero que les haya gustado. Tengo más de estos rompecabezas que quisiera compartir con ustedes.

Echando código: ¿Como encontrar si hay elementos duplicados en una lista grande de números?

Bueno, suponga que le dan el siguiente problema:

Tiene una lista desordenada de números de tamaño N; Cada elemento puede estar entre 0 y N. Le preguntan cual es la forma más rápida de saber si dicha lista tiene elementos duplicados, utilizando la menor cantidad de memoria posible y en un tiempo constante.

¿Como lo resolvería usted?

Usted podría comenzar resolviendo este problema contando cuantas ocurrencias de cada número aparecen en la lista. Para ello podría guardarlas en un arreglo asociativo (HashMap) el cual tiene tiempo de accesso constante. Pero el problema es que si usted tiene muchisimos números repetidos, entonces va a gastar memoria que jode…

Bueno, si alguna vez usted vió corrimiento de bits ala izquierda y mascaras de bits (en la ULA yo lo aprendí a hacer en una materia que se llama sistemas lógicos :)) entonces vera que el algoritmo se puede simplificar bastante simplemente dandole una mascara distinta a cada número, guardandolos a todos en una variable entera. Si recuerda bien, cada vez que corremos un bit a la izquierda es como si estuvieramos elevando a la n dicho número, donde n es la cantidad de bits que corremos a la izquierda.

¿Fumado? Si, pero el concepto es muy arrecho 😀

OK, no siga leyendo, pienselo un rato y vaya al frente de su computadora.

¿Ya terminó?, Veamos entonces el código en Java:

   1:/**
2: * You are given a list of numbers from 0..N; Each element on the array has
3: * a number that goes from 0..N. Find if the array has any duplicates on it.
4: * Well, for this problem I'm going to assume that CPU power is not an issue
5: * but storage space. Also will try to keep access to the list to the minimun.
6: *
7: * @author Jose V Nunez Zuleta
8: * @version 0.1 - 02/28/2005
9: * License: GPL
10: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
11: */
12:public class ArrayDuplicate {
13:
14: /**
15: * So the idea is to count how many ocurrences of the number appears.
16: * We have to scan the whole list in order to find duplicates, so the
17: * worst case is log(n). We will use the fact that each number can be
18: * stored as a mask of bits, and based on the position from 0 to N we
19: * can have each number as f(n)=2^(n-1). We are only interested to see
20: * if there is a duplicate, so we don't really care about the real number
21: * of duplicates.
22: *
23: * @param args - List of unsorted numbers
24: * @throws Exception if the numbers are invalid
25: * @since 0.1
26: */
27: public static void main(String [] args) throws Exception {
28: if (args == null) {
29: throw new
30: IllegalArgumentException("Provide some numbers");
31: }
32:
33: if (args.length == 0) {
34: throw new
35: IllegalArgumentException("Provide some numbers");
36: }
37: int len = args.length;
38:
39: int num = 0;
40: int checksum = 0;
41: for (int i = 0; i < len; i++) {
42: num = Integer.parseInt(args[i]);
43: int mask = numMask(num);
44: // This number is not on the list, so add it!
45: if ( (checksum & mask) == 0 ) {
46: checksum |= mask;
47: } else {
48: System.out.println("Found first duplicate: "
49: + num);
50: break;
51: }
52: }
53: }
54:
55: /**
56: * f(n)=2^(n-1)
57: * @param number
58: * @return int
59: */
60: public static int numMask(int number) {
61: return 1 << number;
62: }
63:
64:}

Una corrida de ejemplo:

[josevnz@localhost Arrays]$ javac ArrayDuplicate.java -d .
[josevnz@localhost Arrays]$ java ArrayDuplicate 2 3 5 8 7 8 90
Found first duplicate: 8
[josevnz@localhost Arrays]$ java ArrayDuplicate 2 3 5 100 7 8 90 2
Found first duplicate: 2
[josevnz@localhost Arrays]$ java ArrayDuplicate 2 3 5 100 7 8 90 0
[josevnz@localhost Arrays]$

Puede bajarse el código desde acá.

¿Se le ocurre otra idea de como ver si hay duplicados?

Echando código: ¿Como obtener un número de una secuencia, rápidamente?

Les tengo un problemita: Suponga que a usted le dan una secuencia desordenada de números (un arreglo de enteros), desde el 1 hasta el 1000, con uno de ellos perdido en la secuencia. Le piden (si, siempre alguien le pide algo ;)) que diga que número está perdido. Obviamente puede utilizar la computadora, pero tiene una restricción: No puede crear estructura de datos adicionales, como por ejemplo la lista de números ordenada para buscar el número perdido.

¿Piensa que es inútil?. Pienselo otra vez, esto lo preguntan en entrevistas de vez en cuando y no es tan dificil de resolver.

Una pista: Una forma de resolverlo sería marcar que números están en la secuencia, para luego volver a revisar (esta vez contando desde 1 hasta 1000) y así ver quien falta. Sin embargo esto es muy ineficiente ya que hay que contar dos veces, además de hay que almacenar que números fueron visitados.
Pista dos: Empiece con una lista más pequeña, a ver si logra obtener un algoritmo.

No siga leyendo, pienselo un poco más…

OK, ya se rindio. Que chimbo :). Bueno, la solución es simple: Usted puede saber cual es la suma teorica de todos los números de 1 hasta 1000, y si usted suma la secuencia que le dieron y resta ambas sumas entonces allí está su número. Para optimizar más el algoritmo, usted puede calcular la suma de una secuencia conocida con la siguente formula:

suma = n(n+1)/2, donde n es el número más grande de la secuencia.

Así, para n=1000 tenemos que suma = 500000.

Aqui le dejo un pedazo de código en Java (la lógica es la misma en cualquier lenguaje):

   1:/**
2: * This program shows how to find a missing number on a sequence of numbers
3: * @author Jose V Nunez
4: * @version 0.1 - 02/27/2005
5: * License: GPL
6: * Blog: El Angel Negro - http://elangelnegro.blogspot.com
7: */
8:
9:import java.util.Random;
10:import java.util.ArrayList;
11:
12:public class FindNumber {
13:
14: public static final int MAX_NUMBERS = 1000;
15:
16: /**
17: * Command line processing
18: * @param args - ignored
19: * @throw Throwable
20: */
21: public static final void main(String [] args) throws Throwable {
22:
23: Random ran = new Random();
24: Integer [] numbers = null;
25: ArrayList list = new java.util.ArrayList(MAX_NUMBERS);
26: // Get a list of unique random numbers
27: for (int i=0; i < MAX_NUMBERS - 1; i++) {
28: while (true) {
29: Integer num = new Integer(
30: ran.nextInt(MAX_NUMBERS) + 1);
31: if (! list.contains(num)) {
32: list.add(num);
33: break;
34: }
35: }
36: }
37: System.out.println(list);
38: long teorSum = (MAX_NUMBERS * (MAX_NUMBERS + 1)) / 2;
39: long realSum = 0;
40: numbers = (Integer []) list.toArray(new Integer[0]);
41: // Now get the sum of the real sequence
42: int len = numbers.length;
43: for (int i = 0; i < len ; i++) {
44: realSum += numbers[i].intValue();
45: }
46: System.out.println("The missing number is: " +
47: (teorSum - realSum) );
48:
49: }
50:}

Por ejemplo, para revizar una lista de 10 números:

[josevnz@localhost test]$ javac FindNumber.java -d .
[josevnz@localhost test]$ java FindNumber
[1, 5, 10, 6, 9, 7, 4, 2, 8]
The missing number is: 3
[josevnz@localhost test]$

Y puede bajarse el código de aqui.

Echando código: Como conectarse a una base de datos usando Perl

Bueno, dado que últimamente sólo he puesto código de Java, vamos a hacerle un cariñito a Perl 🙂

Resulta que Perl también tiene una API muy fácil de usar llamada DBI; Cada base de datos a su vez cuenta con un módulo especializado llamado DBD::XXX. Así hay modulos para PostgreSQL (DBD:Pgsql), MySQL (DBD::Mysql), Sybase (DBD::Sybase) y así sucesivamente.

¿Que tal fácil es de usar?. Bueno, este pequeño programa se conecta a una base de datos MySQL y hace un simple ‘select count(*)’:

   1:#!/usr/bin/perl

2:# Author: Jose Vicente Nunez Zuleta (josevnz@yahoo.com).
3:#
4:use DBI;
5:use DBD::mysql;
6:use strict;
7:
8:my $user = "bugs";
9:my $password = "xxxx";
10:my $database = "bugs";
11:my $driver = "Mysql";
12:my $host = "localhost";
13:my $port = 3306;
14:
15:my $sql = <<SQL
16:SELECT count(*) FROM bugs
17:SQL
18:;
19:
20:my $dsn = "DBI:mysql:database=$database;host=$host;port=$port";
21:my $con = undef;
22:my $res = undef;
23:eval {
24: DBI->connect($dsn, $user, $password);
25:
26: $res = $con->prepare($sql);
27: $res->execute();
28: while (my ($count) = $res->fetchrow()) {
29: print("$count\n");
30: }
31:};
32:if ($DBI::errstr) {
33: die "$DBI::errstr";
34:}
35:
36:if (defined $res) {
37: $res->finish();
38:}
39:if (defined $con) {
40: $con->disconnect();
41:}
42:
43:__END__

Estos modulos los puede conseguir en CPAN (la base de datos de software para Perl más grande del mundo). Puede empezar con este tutorial si de verdad quiere aprender más.

Echando código: Obteniendo la metadata de una base de datos en Java



Más de una vez me tocó revizar si podía conectarme a una base de datos después de la instalación; Normalmente estas base de datos eran Open Source (MySQL, PostgreSQL) o comerciales (Oracle, Sybase). Cada una de ellas tiene una herramienta nativa que permite ejecutar SQL desde la línea de comando.

Por ejemplo, para PostgreSQL usted puede utilizar el comand ‘psql‘:

psql -U postgres -d template1 -h 127.0.0.1

Y para Sybase puede utilizar el comando ‘isql:’

isql -U sa -P -S localhost -D tempdb

¿No tienen nada que ver, verdad?. Bueno, viene Java al rescate. Java cuenta con un API estandar para conectarse a base de datos llamada ‘JDBC‘. JDBC ofrece métodos consistentes sin importar el tipo de base de datos, lo cual hace la programación mucho más fácil.

¿Y que tipo de información podemos obtener con el API de JDBC acerca de la base de datos? Bueno, esa parte si es dependiente del driver (manejador) particular con el que nos conectamos a la base de datos; Si un método no es soportado entonces lo más seguro es que Java arroja una ‘MethodNotImplementedException‘, asique es bueno revizar el manual del vendedor antes de utilizarlo para evitar sorpresas.

Este no es un tutorial completo de JDBC, pero si le voy a mostrar el código de un programa que escribí hace tiempo para probar instalaciones nuevas de BD; No es perfecto pero le dará una idea de todo lo que se puede hacer. El ejemplo está corriendo contra una base de datos Sybase 12.5.1 en Linux:

   1:import java.sql.Connection;

2:import java.sql.DatabaseMetaData;
3:import java.sql.DriverManager;
4:import java.sql.ResultSet;
5:import java.sql.SQLException;
6:import java.util.ResourceBundle;
7:
8:/**
9: * This program performs metadata tests on a given database.
10: * License: LGPL
11: * @author Jose Vicente Nunez Zuleta (josevnz@yahoo.com)
12: * @version 0.1 - 05/06/2003
13: */
14:public class TestJDBC {
15:
16: /**
17: * Command line processing
18: * @param args Currently ignored
19: * @throws Exception If any of the required properties is missing
20: */
21: public static void main(String [] args) throws Exception {
22: Connection con = null;
23: ResultSet result = null;
24: ResultSet result2 = null;
25: DatabaseMetaData metadata = null;
26: try {
27: // Connect to the database
28: ResourceBundle bundle = ResourceBundle.getBundle("TestJDBC");
29: System.out.println("Using driver: " + bundle.getString("driver"));
30: Class.forName(bundle.getString("driver")).newInstance();
31: System.out.println("Requesting connection using: user='" +
bundle.getString("user") +
"', password='" + bundle.getString("password") + "', url='" +
bundle.getString("url") + "'");
32: con = DriverManager.getConnection(bundle.getString("url"),
bundle.getString("user"), bundle.getString("password"));
33: System.out.println("Got connection");
34:
35: // Retrieve the database metadata information
36: metadata = con.getMetaData();
37: result = metadata.getCatalogs();
38: String catalog = null;
39: while(result.next()) {
40: System.out.println("Catalog: " + result.getString(1));
41: catalog = result.getString(1);
42: }
43: result.close();
44: // Get information about a catalog and table if both are defined
45: if ( (bundle.getString("catalog") != null) &&
(bundle.getString("catalog").length() > 0) &&
(bundle.getString("tableName") != null) &&
(bundle.getString("tableName").length() > 0)) {
46: result = metadata.getTables(bundle.getString("catalog"),
null
, bundle.getString("tableName"), null);
47: while(result.next()) {
48: System.out.println("Table name: " +
result.getString("TABLE_NAME"));
49: }
50: result.close();
51: System.out.println("Getting the best identifiers for table "
+
bundle.getString("tableName"));
52: result = metadata.getIndexInfo(bundle.getString("catalog"), null,
bundle.getString("tableName"), true, false);
53: while(result.next()) {
54: if (result.getString("INDEX_NAME") != null) {
55: System.out.println("\t\tBest id for the table: "
+
result.getString("COLUMN_NAME"));
56: }
57: }
58: result.close();
59: }
60: if ( (bundle.getString("catalog") != null) &&
(bundle.getString("catalog").length() > 0)
&
& (bundle.getString("procedureName") != null) &&
(bundle.getString("procedureName").length() > 0)) {
61: result = metadata.getProcedureColumns(bundle.getString("catalog"),
null, bundle.getString("procedureName"), null);
62: while(result.next()) {
63: System.out.println("Procedure parameter: " +
result.getString("COLUMN_NAME"));
64: System.out.println("\t\t" +
result.getString("COLUMN_NAME") + " Is there\n");
65: }
66: }
67: } catch (SQLException sqlExp) {
68: System.err.println("Error code #: " + sqlExp.getErrorCode());
69: System.err.println("Error string : " + sqlExp.toString());
70: System.err.println("SQLState: " + sqlExp.getSQLState());
71: sqlExp.printStackTrace();
72: } catch (Exception exp) {
73: exp.printStackTrace();
74: } finally {
75: if (result != null) {
76: try { result.close(); } catch (SQLException ignore) {};
77: }
78: if (result2 != null) {
79: try { result2.close(); } catch (SQLException ignore) {};
80: }
81: if (con != null) {
82: try { con.close(); } catch (SQLException ignore) {}
83: }
84: }
85: }
86:}

Y el archivo de configuracion (ResourceBundle):

   1:user=postgres

2:#user=XXXX
3:#password=XXXX
4:password=
5:url=jdbc:postgresql:dbsrv:5432/template1
6:#url=jdbc:sybase:Tds:dbsrv:4100/tempdb
7:#driver=com.sybase.jdbc2.jdbc.SybDriver
8:driver=org.postgresql.Driver
9:tableName=cmo_details
10:#catalog=SECURITIESDB
11:#procedureName=dealpool_bucket
12:catalog=
13:procedureName=

La salida del programa es como sigue:

[josevnz@god jdbc]$ java TestJDBC

Using driver: com.sybase.jdbc2.jdbc.SybDriver

Requesting connection using: user=’XXXX’, password=’XXXX’, url=’jdbc:sybase:Tds:dbsrv:4100/tempdb’

Got connection

Catalog: MYDB1

Catalog: MYDB2

Catalog: SECURITIESDB

Catalog: master

Catalog: model

Catalog: sybsystemdb

Catalog: sybsystemprocs

Catalog: tempdb

Table name: cmo_details

Getting the best identifiers for table cmo_details

Best id for the table: dealname

Best id for the table: groupnumber

Procedure parameter: RETURN_VALUE

RETURN_VALUE Is there

Procedure parameter: @deal_name

@deal_name Is there

Procedure parameter: @groupnumber

@groupnumber Is there

Procedure parameter: @total_currentbalance

@nb_total_currentbalance Is there

Procedure parameter: @debug_flag

@debug_flag Is there

[josevnz@god jdbc]$

Como siempre, espero haberle despertado su curiosidad 🙂

Echando código: Usando ‘referencias débiles’ en Java



Java tiene desde hace tiempo (Java 2 para seer exacto) el concepto de ‘referencias débiles’. Su uso nos puede permitir mejorar el uso de la memoria en nuestra aplicación y en ciertos casos mejorar su desepeño.

Suponga que tenemos un programa que lee desde un archivo de texto una serie de líneas, cada una de ellas con un flujo de caja y una tasa de interés justo al final. El programa toma toda esta información y procede a imprimir el valor neto presente (NPV) por pantalla. Usando la clase ‘BigDecimal’ nos aseguramos de que el cálculo es exacto hasta el último decimal, pero también sabemos esta clase es más lenta que usar un dato de tipo double directamente.

El archivo de ejemplo luce como esto:

   1:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5

2:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
3:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
4:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
5:10000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
6:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
7:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
8:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
9:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
10:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
11:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
12:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
13:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
14:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
15:<....omitiendo lineas repetídas....>
98:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.7
99:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5
100:-1000.0, 500.0, 400.0, 300.0, 200.0, 100.0,0.5

El código de el programa que hace el cálculo:

Y por supuesto en mi estilo perezoso, un pequeño script para llamar a mi programa de Java:

   1:#!/bin/bash

2:declare -r FLAGS=""
3:CLASSPATH="$CLASSPATH:/home/josevnz/java/effective:."
4:exec java -classpath $CLASSPATH $FLAGS com.blogspot.elangelnegro.math.NPV $1 $2

La salida del programa en su primera version. Note los valores de consumo de memoria y tiempo de ejecución:

[josevnz@localhost effective]$ ./NPV.sh NPV.data nc

Used memory: 153928

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: 10652.7

….

NPV: -347.3

NPV: -347.3

NPV: -475.5

NPV: -347.3

NPV: -347.3

Used memory: 155688

Execution time: 1030 miliseconds

[josevnz@localhost effective]$

¿Qué se puede hacer para mejorar el desempeño?. Bueno, una teoría dice que si las entradas de una rútina son las mismas y el resultado que se produce es el mismo, entonces pudieramos colocarlo en un caché; El problema aquí es como decidir que tamaño es el adecuado para el caché. Java cuenta con un tipo de referencias ‘debiles’ las cuales son reclamadas por el recolector de basura de la máquina virtual si no hay nadie usandola. En este caso podemos usar un ‘WeakHashMap‘ y le dejamos a Java la tarea de decidir que referencias eliminar (en teoría la eliminación de las referencias ocurre cuando llamamos cualquier método en esta clase).

Lo que hacemos ahora es proporcionarle una referencia a un java.lang.ref.WeakHashMap a un método ‘wrapper’ el cual verificará si el resultado ya fué calculado. De ser así, retornamos el valor inmediatamente, de lo contrario, lo calculamos, lo guardamos en el caché y entonces lo retornamos a quien nos llama:

   1:package com.blogspot.elangelnegro.math;

2:
3:import java.math.BigDecimal;
4:
5:import java.io.IOException;
6:import java.io.FileReader;
7:import java.io.BufferedReader;
8:
9:import java.lang.ref.WeakReference;
10:import java.util.Map;
11:import java.util.HashMap;
12:
13:/**
14: * This class shows how to use the BigDecimal class for numeric calculation that require to be exact.
15: * This particular class implements the formula of present value
16: * <ul>
17: * <li> http://www.investopedia.com/articles/03/101503.asp
18: * <li> http://www.developer.com/java/other/article.php/631281
19: * <li> http://www.developer.com/java/article.php/788311
20: * </ul>
21: * @author Jose Vicente Nunez Zuleta (josevnz@yahoo.com)
22: * @version 0.1
23: */
24:public final class NPV {
25:
26: /**
27: * Constant used on the calculation of the NPV
28: */
29: private static final BigDecimal ONE = new BigDecimal("1.0");
30:
31: /**
32: * A primitive way to calculate the power of a number.
33: * @param number the number to multiply
34: * @param power How many times
35: * @return The number
36: */
37: private static BigDecimal power(BigDecimal number, int power) {
38: BigDecimal powerc = number;
39: for (int j=1; j < power; j++) {
40: powerc = powerc.multiply(number);
41: }
42: return powerc;
43: }
44:
45: private static final IllegalArgumentException ILLEGAL_ARGUMENT_EXCEPTION =
new
IllegalArgumentException();
46:
47: /**
48: * Calculate the Net Present Value for a given set of CashFlows and
a
discount rate
49: * @param cashflows The Cashflows as BigDecimal objects.
cashflow[cashflows.length - 1] is the discount rate
50: * @return The discount rate as a BigDecimal
51: */
52: public static BigDecimal getNPV(String [] cashflows) {
53: BigDecimal pv = new BigDecimal(cashflows[0]);
54: int length = cashflows.length - 1;
55: BigDecimal discountRate = new BigDecimal(cashflows[length]);
56: for (int i=1; i < length; i++) {
57: pv = pv.add(new BigDecimal(cashflows[i]).divide(
58: power(discountRate.add(ONE), i), BigDecimal.ROUND_HALF_EVEN)
59: );
60: }
61: return pv;
62: }
63:
64: /**
65: * Calculate the Net Present Value for a given set of CashFlows and a discount rate.
66: * http://www-106.ibm.com/developerworks/java/library/j-arrays/
67: * @param cashflows The Cashflows as BigDecimal objects. cashflow[cashflows.length
- 1] is the discount rate
68: * @param cache External cache provided to store the results from previous
calculations

69: * @param key An artifically created key to the NPV value. Is faster to
compare
a String than a whole array, so the more help the better...
70: * @return The discount rate as a BigDecimal
71: */
72: public static BigDecimal getNPV(String [] cashflows, Map cache, String key) {
73: WeakReference ref = (WeakReference) cache.get(key);
74: BigDecimal pv = null;
75: if ( ref == null) {
76: pv = getNPV(cashflows);
77: cache.put(key, new WeakReference(pv));
78: } else {
79: pv = (BigDecimal) ref.get();
80: }
81: return pv;
82: }
83:
84: /**
85: * Command line entry point
86: * @param args The location of the data file. Each cashflow is separated
by
a ',' and the last number is the interest rate.
87: * @throws IOException
88: */
89: public static void main(String [] args) throws IOException {
90: BufferedReader reader = null;
91: boolean useCache = false;
//
We use a boolean because we will do repeated comparisons here
92: Runtime runtime = Runtime.getRuntime();
93: long start = System.currentTimeMillis();
94: HashMap cache = null;
95: long end = 0;
96: long linecount = 1;
97: if (! ((args != null) && (args.length == 2))) {
98: throw ILLEGAL_ARGUMENT_EXCEPTION;
99: } else {
100: if (args[1].equals("c")) {
101: useCache = true;
102: cache = new HashMap();
103: } else if (args[1].equals("nc")) {
104: useCache = false;
105: } else {
106: throw ILLEGAL_ARGUMENT_EXCEPTION;
107: }
108: // Show the memory usage before reading the whole file
109: System.out.println("Used memory: " + (runtime.totalMemory() -
runtime.freeMemory()));
110: }
111: try {
112: reader = new BufferedReader(new FileReader(args[0]));
113: for (String line = reader.readLine(); line != null; line =
reader.readLine(), linecount++) {
114: if (! useCache) {
115: System.out.println("NPV: " + getNPV(line.split(",")));
116: } else {
117: System.out.println("NPV: " +
getNPV
(line.split(","), cache, line));
118: }
119: }
120: // Show the memory usage after calculating the memory usage from the file
121: if (cache != null) {
122: cache.clear();
123: }
124: System.gc();
125: System.out.println("Used memory: " + (runtime.totalMemory() -
runtime.freeMemory()));
126: } catch (IOException ioexp) {
127: throw ioexp;
128: } catch (NumberFormatException nfe) {
129: System.err.println("Error at line: " + linecount);
130: throw nfe;
131: } finally {
132: if (reader != null) {
133: try {
134: reader.close();
135: } catch (IOException ignore) {
136: // Empty on purpose
137: }
138: }
139: end = System.currentTimeMillis();
140: System.out.println("Execution time: " + (end-start) + " miliseconds");
141: }
142: }
143:}



La magia ocurre entre las lineas 64-82. Ahora veamos el uso de memoria y los tiempos de ejecución:

[josevnz@localhost effective]$ ./NPV.sh NPV.data c

Used memory: 153944

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: 10652.7

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: -347.3

NPV: -347.3

….

NPV: -347.3

NPV: -475.5

NPV: -347.3

NPV: -347.3

Used memory: 430184

Execution time: 500 miliseconds

Y note como varia el uso de la memoria se incrementa mucho más y el tiempo de ejecución disminuye (la mitad). Si bien la técnica es útil, note como nunca hay un almuerzo grátis (free lunch).

Espero que la técnica le resulte útil, aqui les dejo un pequeño tutorial y espero sus comentarios por acá 🙂

Como empezar como un SA: Proyecto Admire



Como empezar como un SA

Originally uploaded by angelnegro.

Esta es un viejo articulo, publicado por alla en 1997 que habla de el grupo de administradores de sistemas de el grupo “Admire” (Administradores de Red) de la Universidad de Los Andes.

En la foto, de izquierda a derecha empezando por el chamo de franela blanca: Daniel Pradilla, Freddy Rojas, Sylvia Delgado, Francisco Rincón, Luís Marquez, Ricardo Fernández, Edgard Montilla, Nicolas Ruiz, Jose V Núñez (YO), René Acosta, Crox Sanchez, Erica Oropeza.

En la fotografía aparecen “los hackers” responsables de coordinar el grupo, Daniel Pradilla y Nicolas Ruiz (hasta ahora los administradores de sistemas más talentosos con los que me he topado). Yo junto con el “pana” Luis Marquez (Chiguire) nos caiamos a golpes en Ingenieria, tratando me mantener el barco a flote.

Es curioso como alguien se decide a trabajar en algo así; En aquel momento me pagaban la jugosa suma de ¡Bs. 90000! al año ($20 dolares al cambio actual), por 16 horas semanales mientras trabajaba y estudiaba. Lo triste es que yo ganaba más que una prima que era médico que en aquel entonces trabajaba en el seguro social :(.

¿Como me metí en ese lio? Bueno, la historia resumida en breves pasos se resume asi (esto empieza a finales de 1995):

    Yo veia como los profesores trabajan en estaciones de trabajo “Sun” en Ingeniería. Yo queria bajarme programas de Internet usando FTP, Gopher, Archie (si, Mosaic apareció un año después esto es pre-web). Un profesor me pescó un día y me dijo asi

    • Rafel: “¡Hay pajarito, esto es sólo para profesores!”
    • Yo: ¿Como hago para abrir una cuenta?
    • Rafael: Tienes que concursar como preparador de PDI (Programación digital I, en Pascal). Luego me dejó trabajando tranquilo (al tiempo me enteré que él era un SA y sólo estaba revizando que quien usaba las estaciones, habia mucha demanda y los profesores iban primero).

Concursé, quedé y me dieron 512K de espacio en quota para bajar programas, y mi propia cuenta de Unix en Sun OS. ¡Yohoooo!. Sin embargo faltaba algo…

Pero 512k eran muy poquito; Yo noté que habia un grupito de personas que eran los que mantenian la red y tenían accesso a todos los secretos y rincones de los servidores; Ellos creaban usuarios, instalaban nuevas máquinas, decidian quien podía trabajar y quien no. También sabian programar en lenguajes extraños como Perl, sabian C. Asi que un dia le pregunte a una de las administradoras de la red (si era una chica, Tania, de la cual algún día contaré historias curiosas. Por ahora sólo sabrán que fumaba mucho):

  • Yo: ¿Como hago para ser tener espacio de disco ilimitado?”
  • Tania: ¿Para que quieres eso?
  • Yo: Bueno….
  • Tania: Tienes que concursar. En 6 meses se van a abrir unas vacantes
  • Yo: ¿Y que tengo que estudiar?
  • Tania: Hmmm, preguntale a Chucho. El te dirá.

Resulta que Jesus (de allí Chucho) y Julio (otro administrador de sistemas) me dieron material para leer… en un floppy de 3.25”. Durante 6 meses hicimos instalaciones de máquinas, aprendimos algo de Unix y nos hicieron trabajar en las cosas más ladillas que se puedan imaginar. Pero la iniciación pagó: al final de los 6 meses hubo un concurso y quedé junto con un amigo; Lo que no sabiamos era la cantidad de trabajo tan bestial que se nos caia encima y lo poco que sabiamos. El primer día de trabajo una de las Sun decidió morirse (falla en el disco duro) y ese día nos tocó (junto con Rafael que fué quien acomodó el lio) enterarnos de como trabajaba Sendmail, como formatear un disco en SunOS y de como explicarle a los usuarios que no tendrían email porque sus cuentas estaban muertas (si, los viejos dias de recuperar el respaldo del disco usando tar desde una cinta. Y también los viejos días de mentir cuando no sabias algo). Ya en ese entonces Nicolas estaba trabajando como SA y Daniel Pradilla entraría unos meses después (por ese entonces el trabajaba en el Laboratorio de Comunicaciones de la Escuela de Electrica de la ULA).

Meses después Chucho nos mostraría Mosaic para Sun OS (el primer navegador) y Nestor Angulo Reina (un querido amigo que ya no está con nosotros, quien trabajó en el Laboratorio de Cominucaciones con Daniel Pradilla) nos daría a mi y a mi papá 44 discos con Slackware para que pudieramos aprender Unix desde nuestras casas.

Ya de allí en adelante comenzaron nuestras aventuras y desventuras como administradores de sistemas.

El Angel Negro: Adios a Los Ineditos

Un poco de historia. Volvamos atrás en el tiempo, el año es 1997 y un estudiante de Ingenieria de Sistemas se decide a hacer una pagina web en la cual coloca sus tutoriales sobre administración de sistemas, inquietudes de musica rock y poesía (si no ha caido en cuenta, si ese era yo…)

Lo curioso es que nunca se me ocurrió que una periodista de el nacional se iba a interesar en mi sitio web en la Universidad de Los Andes, “El Angel Negro” y mucho menos que iba a publicar un articulo acerca de el sitio en esa epoca (recuerden, los editores HTML eran vistos como algo depinga, ‘dot.com’ estaba de moda).

Algo que siempre me dio risa fue como los “Blogs” se volvieron una forma depinga de mostrar el pensar de un individuo, cuando casi TODO el mundo tenia una pagina web personal ya por allá en 1997 (las maravillas del mercadeo en inventar terminos inutiles).

¡Que tiempos aquellos!. Hoy en día el sitio web ya no existe, asi que tendrán que conformarse con esta versión del sitio web 🙂

Redes para todo el mundo: ¿Caracas la primera cuidad de Latinoamerica con Wireless en todos lados?

Pues según el sitio web descifrado.com va a ser asi, ya Propatria tiene Wireless. De ser verdad, esto va a generar un monton de entradas de dinero, a la vez que ahora será posible desarrollar servicios que dependan de este tipo de tecnología, los cuales estarán disponibles para toda la población.

Muy buenas noticias para los Caraqueños.