I am running the same F# code with the two versions of fsi.exe which I can find under my FSharp-2.0.0.0 install:
C:\Program Files\FSharp-2.0.0.0\bin\fsi.exe - Microsoft (R) F# 2.0 Interactive build 2.0.0
C:\Program Files\FSharp-2.0.0.0\v4.0\bin\fsi.exe - Microsoft (R) F# 2.0 Interactive build 4.0.30319.1
What I find is that the same code runs about three times faster on the 2.0.0.0 build. Does this make any sense? Is there something messed up with my environment or possibly code??
Incidentally, the reason I am trying to use the v4.0 build is to be able to use the TPL and compare sequential and parallel implementations of my code. When my parallel implementation was much slower than the sequential one, after much head-scratching I realized that the parallel version was running under a different fsi.exe, and that's when I realized that the same (sequential) version of the code is much slower under version 4.0.
Thanks in advance for any help
IS
The code:
module Options
//Gaussian module is from http://fssnip.net/3g, by Tony Lee
open Gaussian
//The European Option type
type EuropeanOption =
{StockCode: string
StockPrice: float
ExercisePrice: float
NoRiskReturn: float
Volatility: float
Time: float
}
//Read one row from the file and return a European Option
//File format is:
//StockCode<TAB>StockPrice,ExercisePrice,NoR开发者_如何学编程iskReturn,Volatility,Time
let convertDataRow(line:string) =
let option = List.ofSeq(line.Split('\t'))
match option with
| code::data::_ ->
let dataValues = (data.Split(','))
let euopt = {StockCode = code;
StockPrice = float (dataValues.[0]);
ExercisePrice = float (dataValues.[1]);
NoRiskReturn = float (dataValues.[2]);
Volatility = float (dataValues.[3]);
Time = float (dataValues.[4])
}
euopt
| _ -> failwith "Incorrect Data Format"
//Returns the future value of an option.
//0 if excercise price is greater than the sum of the stock price and the calculated asset price at expiration.
let futureValue sp ep nrr vol t =
//TODO: Is there no better way to get the value from a one-element sequence?
let assetPriceAtExpiration = sp+sp*nrr*t+sp*sqrt(t)*vol*(Gaussian.whiteNoise |> Seq.take 1 |> List.ofSeq |> List.max)
[0.0;assetPriceAtExpiration - ep] |> List.max
//Sequence to hold the values generated by the MonteCarlo iterations
//50,000 iterations is the minimum for a good aprox to the Black-Scholes equation
let priceValues count sp ep nrr vol t =
seq { for i in 1..count
-> futureValue sp ep nrr vol t
}
//Discount a future to a present value given the risk free rate and the time in years
let discount value noriskreturn time =
value * exp(-1.0*noriskreturn*time)
//Get the price for a European Option and a given number of Monte Carlo iterations (use numIters >= 50000)
let priceOption europeanOption numIters =
let futureValuesSeq = priceValues numIters europeanOption.StockPrice europeanOption.ExercisePrice europeanOption.NoRiskReturn europeanOption.Volatility europeanOption.Time
//The simulated future value is just the average of all the MonteCarlo runs
let presentValue = discount (futureValuesSeq |> List.ofSeq |> List.average) europeanOption.NoRiskReturn europeanOption.Time
//Return a list of tuples with the stock code and the calculated present value
europeanOption.StockCode + "_to_" + string europeanOption.Time + "_years \t" + string presentValue
module Program =
open Options
open System
open System.Diagnostics
open System.IO
//Write to a file
let writeFile path contentsArray =
File.WriteAllLines(path, contentsArray |> Array.ofList)
//TODO: This whole "method" is sooooo procedural.... is there a more functional way?
//Unique code for each run
//TODO: Something shorter, please
let runcode = string DateTime.Now.Month + "_" + string DateTime.Now.Day + "_" + string DateTime.Now.Hour + "_" + string DateTime.Now.Minute + "_" + string DateTime.Now.Second
let outputFile = @"C:\TMP\optionpricer_results_" + runcode + ".txt"
let statsfile = @"C:\TMP\optionpricer_stats_" + runcode + ".txt"
printf "Starting"
let mutable stats = ["Starting at: [" + string DateTime.Now + "]" ]
let stopWatch = Stopwatch.StartNew()
//Read the file
let lines = List.ofSeq(File.ReadAllLines(@"C:\tmp\9000.txt"))
ignore(stats <- "Read input file done at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats)
printfn "%f" stopWatch.Elapsed.TotalMilliseconds
//Build the list of European Options
let options = lines |> List.map convertDataRow
ignore(stats <- ("Created Options done at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]")::stats)
printfn "%f" stopWatch.Elapsed.TotalMilliseconds
//Calculate the option prices
let results = List.map (fun o -> priceOption o 50000) options
ignore(stats <- "Option prices calculated at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats)
printfn "%f" stopWatch.Elapsed.TotalMilliseconds
//Write results and statistics
writeFile outputFile results
ignore(stats <- "Output file written at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats)
ignore(stats <- "Total Ellapsed Time (minus stats file write): [" + string (stopWatch.Elapsed.TotalMilliseconds / 60000.0) + "] minutes"::stats)
printfn "%f" stopWatch.Elapsed.TotalMilliseconds
writeFile statsfile (stats |> List.rev)
stopWatch.Stop()
ignore(Console.ReadLine())
I haven't run your code but it looks like you're creating lots of linked lists. That is very inefficient but the representation of lists was changed in recent years and the new representation is slower.
精彩评论