How to calculate square root in sqlite

こ雲淡風輕ζ 提交于 2021-02-18 09:01:56

问题


I need to calculate an euclidean distance in a sqlite database.

Does anyone know how to calculate square roots in sqlite beside writing and loading a dynamic library for math functions?

I am close to resorting to the fast inverse square root algorithm in here http://en.wikipedia.org/wiki/Fast_inverse_square_root though it might to turn into more fun than I need right now.

And as a side note, it'd be great to figure out how to do power (which is the generalized question, and is cleaner coding than multiplying a number by itself).

Thanks,

Simone


回答1:


Well, I have a semi-answer.

Yes it involves a 3rd party, but you don't have to write it yourself : did you check the last extension on this page ?

It includes several math functions, and amongst them is sqrt().




回答2:


Warning: this answer is dependent on the coding language. In my case C#.

User defined SQLite functions was for me a pain to implement. Finally, after a long time of searching I was able to implement it in my C# code. Main function looks like this:

[SQLiteFunction(Arguments = 1, FuncType = FunctionType.Scalar, Name = "Sqrt")]
class Sqrt : SQLiteFunction
{
    public override object Invoke(object[] args)
    {
        return Math.Sqrt(Double.Parse(args[0].ToString()));
    }
}

Registration of custom function:

SQLiteFunction.RegisterFunction(typeof(Sqrt));

And using in select:

SQLiteCommand com = new SQLiteCommand("select sqrt(10.42)", connection);

You can download full example here: http://db.tt/qzeNXwso

Or, if you want only view code (or get through all parts of my code), I paste below full working example code for calculate square root in SQLite database, because is very hard to find any working code for this. To create and run this example do this 6 steps:

  1. Create new project (my name is Sqrt)
  2. Include SQLite reference to your project:
    Solution Explorer -> References (right click: Add reference) -> Assemblies - Extensions - System.Data.SQLite (check) -> OK
  3. Open App.config and replace to this (without this step you maybe get Mixed mode assembly error):

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0"/>
    </startup>
    </configuration>

  4. Replace your Form1.Designer.cs with this code:

    namespace Sqrt
    {
     partial class Form1
     {
     /// <summary>
     /// Required designer variable.
     /// </summary>
     private System.ComponentModel.IContainer components = null;
    
     /// <summary>
     /// Clean up any resources being used.
     /// </summary>
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
     protected override void Dispose(bool disposing)
     {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
     }
    
     #region Windows Form Designer generated code
    
     /// <summary>
     /// Required method for Designer support - do not modify
     /// the contents of this method with the code editor.
     /// </summary>
     private void InitializeComponent()
     {
        this.txb_Input = new System.Windows.Forms.TextBox();
        this.txb_Output = new System.Windows.Forms.TextBox();
        this.label1 = new System.Windows.Forms.Label();
        this.label2 = new System.Windows.Forms.Label();
        this.btn_Calcualte = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // txb_Input
        // 
        this.txb_Input.Location = new System.Drawing.Point(131, 12);
        this.txb_Input.Name = "txb_Input";
        this.txb_Input.Size = new System.Drawing.Size(201, 20);
        this.txb_Input.TabIndex = 0;
        // 
        // txb_Output
        // 
        this.txb_Output.BackColor = System.Drawing.Color.WhiteSmoke;
        this.txb_Output.Location = new System.Drawing.Point(131, 38);
        this.txb_Output.Name = "txb_Output";
        this.txb_Output.ReadOnly = true;
        this.txb_Output.Size = new System.Drawing.Size(201, 20);
        this.txb_Output.TabIndex = 0;
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(12, 15);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(31, 13);
        this.label1.TabIndex = 1;
        this.label1.Text = "Input";
        // 
        // label2
        // 
        this.label2.AutoSize = true;
        this.label2.Location = new System.Drawing.Point(12, 41);
        this.label2.Name = "label2";
        this.label2.Size = new System.Drawing.Size(39, 13);
        this.label2.TabIndex = 1;
        this.label2.Text = "Output";
        // 
        // btn_Calcualte
        // 
        this.btn_Calcualte.Location = new System.Drawing.Point(257, 64);
        this.btn_Calcualte.Name = "btn_Calcualte";
        this.btn_Calcualte.Size = new System.Drawing.Size(75, 23);
        this.btn_Calcualte.TabIndex = 2;
        this.btn_Calcualte.Text = "Calculate";
        this.btn_Calcualte.UseVisualStyleBackColor = true;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(344, 98);
        this.Controls.Add(this.btn_Calcualte);
        this.Controls.Add(this.label2);
        this.Controls.Add(this.label1);
        this.Controls.Add(this.txb_Output);
        this.Controls.Add(this.txb_Input);
        this.Name = "Form1";
        this.Text = "Root square example";
        this.ResumeLayout(false);
        this.PerformLayout();
     }
     #endregion
    
     private System.Windows.Forms.TextBox txb_Input;
     private System.Windows.Forms.TextBox txb_Output;
     private System.Windows.Forms.Label label1;
     private System.Windows.Forms.Label label2;
     private System.Windows.Forms.Button btn_Calcualte;
     }
    }
    
  5. Open Form1.cs (code) and replace code with this: using System; using System.Data.SQLite; using System.Windows.Forms;

    namespace Sqrt
    {
        // definition of custom sqlite function
        [SQLiteFunction(Arguments = 1, FuncType = FunctionType.Scalar, Name = "Sqrt")]
        class Sqrt : SQLiteFunction
        {
            public override object Invoke(object[] args)
            {
                return Math.Sqrt(Double.Parse(args[0].ToString())); // return result of math sqrt function
            }
        }
    
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                this.btn_Calcualte.Click += new System.EventHandler(this.btn_Calcualte_Click);
            }
    
            private void btn_Calcualte_Click(object sender, EventArgs e)
            {
                if (txb_Input.Text.Length == 0)
                    return;
                try { SQLiteConnection.CreateFile(AppDomain.CurrentDomain.BaseDirectory + "test.s3db"); }
                catch { }
                SQLiteConnection con = new SQLiteConnection("Data Source=test.s3db");
                SQLiteFunction.RegisterFunction(typeof(Sqrt)); // register custom function
                con.Open();
                SQLiteCommand com = new SQLiteCommand("select sqrt(" + txb_Input.Text.Replace(',', '.') + ")", con); // select result
                string res = com.ExecuteScalar().ToString();
                txb_Output.Text = res;
            }
        }
    }
    
  6. Run, try and enjoy.




回答3:


This is an approximation of sqrt for numbers under 10000. It can be extended for arbitrary numbers, and can be extended to arbitrary precision as needed. This kind of tabular interpolation is what happens in most fast implementations anyway:

case when weight >= 1 and weight<=10 then 1+0.240253073*(weight-1) 
     when weight>=10 and weight<=100 then 3.16227766+0.075974693*(weight-10) 
     when weight>=100 and weight<=1000 then 10+0.024025307*(weight-100)      
     else 31.6227766+0.007597469 *(weight-1000) end

And there's the curious fact that each factor you use in such a power-of-10 square root interpolation table is 0.316227766 times the previous one - so you can make this work for an arbitrarily large number, or even stuff a table full of these values to make it work for any number. (Could that lead to some compression here?)

Or this cute one for log10 of integers, using the length function (an interpolation table might work better here, but I like that log10 and length() are similar, and that this works for any integer - no interpolation needed.

 ((length(x)+length(x*2)+length(x*3)
  +length(x*4)+length(x*5))/5.0)-1.0

A better math head than I can probably come up with better and denser approximations. Considering that most sqrt functions in c use approximations anyway - this is a pretty good solution.

This is the only native way of doing it.




回答4:


As far as I know - you can't do that using only core functions.

Here is the list of native functions Core functions and a list of aggregate functions Aggregate functions.

To solve your problem, you can write your own UDF (user defined function) as illustrated HERE



来源:https://stackoverflow.com/questions/12731941/how-to-calculate-square-root-in-sqlite

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!